Skip to content

Commit

Permalink
SIO-1985 Handle Submission.DoesNotExist in evalmgr processing
Browse files Browse the repository at this point in the history
Change-Id: I1b7aa916264dd902a43194cd89b35b3414d53be2
  • Loading branch information
lewapkon committed Jun 6, 2017
1 parent 51374f1 commit aa0fd01
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 40 deletions.
72 changes: 46 additions & 26 deletions oioioi/contests/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import pprint
import socket
import time
from functools import wraps
from smtplib import SMTPException
from django.core.mail import mail_admins
from django.db import transaction
from oioioi.contests.models import Contest, ProblemInstance, Submission, \
from oioioi.base.utils.db import require_transaction
from oioioi.contests.models import ProblemInstance, Submission, \
SubmissionReport, FailureReport

logger = logging.getLogger(__name__)
Expand All @@ -17,6 +19,33 @@
WAIT_FOR_SUBMISSION_SLEEP_SECONDS = 1


#TODO: Improve after migration to Python 3:
# def _get_submission_or_skip(*args, submission_class=Submission)
def _get_submission_or_skip(*args, **kwargs):
submission_class = kwargs.get('submission_class', Submission)

def wrapper(fn):
"""A decorator which tries to get a submission by id from env or skips
the decorated function if the submission doesn't exist.
"""
@wraps(fn)
@require_transaction
def decorated(env, *args, **kwargs):
if 'submission_id' not in env:
return env
try:
submission = submission_class.objects.get(
id=env['submission_id'])
except Submission.DoesNotExist:
return env
return fn(env, submission, *args, **kwargs)
return decorated

if len(args) == 1:
return wrapper(args[0])
return wrapper


def wait_for_submission_in_db(env, **kwargs):
"""Celery may start handling a submission before it is actually saved
in the DB. This is a workaround for this.
Expand All @@ -30,25 +59,29 @@ def wait_for_submission_in_db(env, **kwargs):


@transaction.atomic
def update_report_statuses(env, **kwargs):
submission = Submission.objects.get(id=env['submission_id'])
@_get_submission_or_skip
def update_report_statuses(env, submission, **kwargs):
problem_instance = submission.problem_instance
reports = SubmissionReport.objects.filter(submission=submission)
problem_instance.controller.update_report_statuses(submission, reports)
return env


@transaction.atomic
def update_submission_score(env, **kwargs):
submission = Submission.objects.get(id=env['submission_id'])
@_get_submission_or_skip
def update_submission_score(env, submission, **kwargs):
problem_instance = submission.problem_instance
problem_instance.controller.update_submission_score(submission)
return env


def update_user_results(env, **kwargs):
with transaction.atomic():
submission = Submission.objects.get(id=env['submission_id'])
try:
submission = Submission.objects.get(id=env['submission_id'])
except Submission.DoesNotExist:
return env

user = submission.user
if not user:
return env
Expand All @@ -70,8 +103,8 @@ def update_user_results(env, **kwargs):


@transaction.atomic
def call_submission_judged(env, **kwargs):
submission = Submission.objects.get(id=env['submission_id'])
@_get_submission_or_skip
def call_submission_judged(env, submission, **kwargs):
contest = submission.problem_instance.contest

if contest is None:
Expand All @@ -85,7 +118,8 @@ def call_submission_judged(env, **kwargs):


@transaction.atomic
def create_error_report(env, exc_info, **kwargs):
@_get_submission_or_skip
def create_error_report(env, submission, exc_info, **kwargs):
"""Builds a :class:`oioioi.contests.models.SubmissionReport` for
an evaulation which have failed.
Expand All @@ -97,14 +131,6 @@ def create_error_report(env, exc_info, **kwargs):
env.get('submission_id', '???'),
pprint.pformat(env, indent=4), exc_info=exc_info)

if 'submission_id' not in env:
return env

try:
submission = Submission.objects.get(id=env['submission_id'])
except Submission.DoesNotExist:
return env

submission_report = SubmissionReport(submission=submission)
submission_report.kind = 'FAILURE'
submission_report.save()
Expand All @@ -117,22 +143,16 @@ def create_error_report(env, exc_info, **kwargs):
return env


def mail_admins_on_error(env, exc_info, **kwargs):
@transaction.atomic
@_get_submission_or_skip
def mail_admins_on_error(env, submission, exc_info, **kwargs):
"""Sends email to all admins defined in settings.ADMINS on each
grading error occurrence.
USES
* `env['submission_id']`
"""

# We don't want to spam admins when the evaluation of a deleted
# submission fails. See also SIO-1254.
try:
if 'submission_id' in env:
Submission.objects.get(id=env['submission_id'])
except Submission.DoesNotExist:
return env

try:
mail_admins("System Error evaluating submission #%s" %
env.get('submission_id', '???'),
Expand Down
9 changes: 5 additions & 4 deletions oioioi/programs/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from oioioi.contests.scores import ScoreValue, IntegerScore
from oioioi.contests.models import Submission, SubmissionReport, \
ScoreReport
from oioioi.contests.handlers import _get_submission_or_skip
from oioioi.programs.models import CompilationReport, TestReport, \
GroupReport, Test, UserOutGenStatus
from oioioi.filetracker.client import get_client
Expand Down Expand Up @@ -417,7 +418,8 @@ def grade_submission(env, kind='NORMAL', **kwargs):
return env


def _make_base_report(env, kind):
@_get_submission_or_skip
def _make_base_report(env, submission, kind):
"""Helper function making: SubmissionReport, ScoreReport,
CompilationReport.
Expand All @@ -435,7 +437,6 @@ def _make_base_report(env, kind):
Returns: tuple (submission, submission_report)
"""
submission = Submission.objects.get(id=env['submission_id'])
submission_report = SubmissionReport(submission=submission)
submission_report.kind = kind
submission_report.save()
Expand Down Expand Up @@ -591,7 +592,8 @@ def fill_outfile_in_existing_test_reports(env, **kwargs):


@transaction.atomic
def insert_existing_submission_link(env, **kwargs):
@_get_submission_or_skip
def insert_existing_submission_link(env, src_submission, **kwargs):
"""Add comment to some existing submission with link to submission view
of present submission.
Expand All @@ -607,7 +609,6 @@ def insert_existing_submission_link(env, **kwargs):
submission_report_id = env['extra_args']['submission_report_id']
submission_report = SubmissionReport.objects.get(id=submission_report_id)
dst_submission = submission_report.submission
src_submission = Submission.objects.get(id=env['submission_id'])
href = reverse('submission', kwargs={'submission_id': dst_submission.id,
'contest_id': env['contest_id']})
html_link = make_html_link(href, _("submission report") + ": " +
Expand Down
11 changes: 6 additions & 5 deletions oioioi/suspendjudge/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.db import transaction

from oioioi.contests.models import Submission
from oioioi.contests.handlers import _get_submission_or_skip
from oioioi.programs.models import ModelProgramSubmission
from oioioi.suspendjudge.models import SuspendedProblem
from oioioi.evalmgr.utils import mark_job_state
Expand All @@ -22,11 +23,11 @@ def _is_hidden_rejudge(env):
return env['is_rejudge'] and 'HIDDEN' in env['report_kinds']


def _is_admin_submission(env):
s = Submission.objects.get(pk=env['submission_id'])
if s.user is not None:
return s.user.has_perm('contests.contest_admin',
s.problem_instance.contest)
@_get_submission_or_skip
def _is_admin_submission(env, submission):
if submission.user is not None:
return submission.user.has_perm('contests.contest_admin',
submission.problem_instance.contest)
return False


Expand Down
7 changes: 4 additions & 3 deletions oioioi/testrun/handlers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from django.db import transaction
from django.utils.text import Truncator

from oioioi.programs.handlers import _skip_on_compilation_error, _make_base_report
from oioioi.programs.handlers import _skip_on_compilation_error, \
_make_base_report, _get_submission_or_skip
from oioioi.testrun.models import TestRunProgramSubmission, TestRunConfig, \
TestRunReport
from oioioi.filetracker.utils import django_to_filetracker_path, \
Expand All @@ -11,7 +12,8 @@

@_skip_on_compilation_error
@transaction.atomic
def make_test(env, **kwargs):
@_get_submission_or_skip(submission_class=TestRunProgramSubmission)
def make_test(env, submission, **kwargs):
"""Creates a testcase *test* from the user input and converts it to
evaluation environment.
Expand All @@ -22,7 +24,6 @@ def make_test(env, **kwargs):
Produced ``environ`` keys:
* ``tests``: a dictionary mapping test names to test envs
"""
submission = TestRunProgramSubmission.objects.get(id=env['submission_id'])
assert submission.kind == 'TESTRUN'
config = TestRunConfig.objects.get(problem__id=env['problem_id'])

Expand Down
5 changes: 3 additions & 2 deletions oioioi/zeus/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from oioioi import evalmgr
from oioioi.base.utils import naturalsort_key
from oioioi.contests.handlers import _get_submission_or_skip
from oioioi.programs.handlers import _skip_on_compilation_error
from oioioi.programs.models import ProgramSubmission, Test
from oioioi.zeus.backends import get_zeus_server
Expand Down Expand Up @@ -41,10 +42,10 @@ def from_csv_metadata(metadata):

@_skip_on_compilation_error
@transaction.atomic
def submit_job(env, kind):
@_get_submission_or_skip(submission_class=ProgramSubmission)
def submit_job(env, submission, kind):
"""Recipe handler that sends the job to Zeus.
"""
submission = ProgramSubmission.objects.get(id=env['submission_id'])
with submission.source_file as f:
source_code = f.read()
return evalmgr.transfer_job(env,
Expand Down

0 comments on commit aa0fd01

Please sign in to comment.