diff --git a/examples/atd_submission.py b/examples/atd_submission.py index 83e02e2..f68ebd7 100644 --- a/examples/atd_submission.py +++ b/examples/atd_submission.py @@ -1,5 +1,4 @@ import os -import time import judge0 @@ -19,8 +18,7 @@ def run_example(client_class, language_id): ) client.create_submission(submission) - time.sleep(1) - client.get_submission(submission) + client.wait(submission) print(f"{submission.status=}") print(f"{submission.stdout=}") diff --git a/examples/atd_submissions.py b/examples/atd_submissions.py index 68c05c5..7f85b58 100644 --- a/examples/atd_submissions.py +++ b/examples/atd_submissions.py @@ -1,5 +1,4 @@ import os -import time import judge0 @@ -25,8 +24,7 @@ def run_example(client_class, lang_id_python, lang_id_c): submissions = [submission1, submission2] client.create_submissions(submissions) - time.sleep(1) - client.get_submissions(submissions) + client.wait(submissions) for submission in submissions: print(f"{submission.status=}") diff --git a/examples/rapid_submission.py b/examples/rapid_submission.py index ad95541..3eb7bc5 100644 --- a/examples/rapid_submission.py +++ b/examples/rapid_submission.py @@ -1,5 +1,4 @@ import os -import time import judge0 @@ -19,8 +18,7 @@ def run_example(client_class, language_id): ) client.create_submission(submission) - time.sleep(1) - client.get_submission(submission) + client.wait(submission) print(f"{submission.status=}") print(f"{submission.stdout=}") diff --git a/examples/rapid_submissions.py b/examples/rapid_submissions.py index 3e4942a..a130dff 100644 --- a/examples/rapid_submissions.py +++ b/examples/rapid_submissions.py @@ -1,5 +1,4 @@ import os -import time import judge0 @@ -25,8 +24,7 @@ def run_example(client_class, lang_id_python, lang_id_c): submissions = [submission1, submission2] client.create_submissions(submissions) - time.sleep(1) - client.get_submissions(submissions) + client.wait(submissions) for submission in submissions: print(f"{submission.status=}") diff --git a/examples/sulu_submission.py b/examples/sulu_submission.py index c513248..2d94c31 100644 --- a/examples/sulu_submission.py +++ b/examples/sulu_submission.py @@ -1,5 +1,4 @@ import os -import time import judge0 @@ -19,8 +18,7 @@ def run_example(client_class, language_id): ) client.create_submission(submission) - time.sleep(1) - client.get_submission(submission) + client.wait(submission) print(f"{submission.status=}") print(f"{submission.stdout=}") diff --git a/examples/sulu_submissions.py b/examples/sulu_submissions.py index 3d08517..850883a 100644 --- a/examples/sulu_submissions.py +++ b/examples/sulu_submissions.py @@ -1,5 +1,4 @@ import os -import time import judge0 @@ -25,8 +24,7 @@ def run_example(client_class, lang_id_python, lang_id_c): submissions = [submission1, submission2] client.create_submissions(submissions) - time.sleep(1) - client.get_submissions(submissions) + client.wait(submissions) for submission in submissions: print(f"{submission.status=}") diff --git a/src/judge0/__init__.py b/src/judge0/__init__.py index d7f6696..d973df8 100644 --- a/src/judge0/__init__.py +++ b/src/judge0/__init__.py @@ -7,6 +7,7 @@ SuluJudge0CE, SuluJudge0ExtraCE, ) +from .retry import MaxRetries, MaxWaitTime, RegularPeriodRetry from .submission import Submission @@ -19,4 +20,7 @@ SuluJudge0CE, SuluJudge0ExtraCE, Submission, + RegularPeriodRetry, + MaxRetries, + MaxWaitTime, ] diff --git a/src/judge0/clients.py b/src/judge0/clients.py index 3bf661f..971af6c 100644 --- a/src/judge0/clients.py +++ b/src/judge0/clients.py @@ -1,7 +1,9 @@ -from typing import Iterable, Union +from typing import Iterable, Optional, Union import requests +from .retry import RegularPeriodRetry, RetryMechanism + from .submission import Submission @@ -160,6 +162,36 @@ def get_submissions( for submission, attrs in zip(submissions, resp.json()["submissions"]): submission.set_attributes(attrs) + def wait( + self, + submissions: Union[Submission, list[Submission]], + *, + retry_mechanism: Optional[RetryMechanism] = None, + ): + if retry_mechanism is None: + retry_mechanism = RegularPeriodRetry() + + if not isinstance(submissions, (list, tuple)): + submissions = [submissions] + + submissions_to_check = { + submission.token: submission for submission in submissions + } + + while len(submissions_to_check) > 0 and not retry_mechanism.is_done(): + self.get_submissions(submissions_to_check.values()) + for token in list(submissions_to_check): + submission = submissions_to_check[token] + if submission.is_done(): + submissions_to_check.pop(token) + + # Don't wait if there is no submissions to check for anymore. + if len(submissions_to_check) == 0: + break + + retry_mechanism.wait() + retry_mechanism.step() + class ATD(Client): def __init__(self, endpoint, host_header_value, api_key): diff --git a/src/judge0/retry.py b/src/judge0/retry.py new file mode 100644 index 0000000..33acc52 --- /dev/null +++ b/src/judge0/retry.py @@ -0,0 +1,68 @@ +import time +from abc import ABC, abstractmethod + + +class RetryMechanism(ABC): + @abstractmethod + def is_done(self) -> bool: + pass + + @abstractmethod + def wait(self) -> None: + pass + + @abstractmethod + def step(self) -> None: + pass + + +class MaxRetries(RetryMechanism): + """Check for submissions status every 100 ms and retry a maximum of + `max_retries` times.""" + + def __init__(self, max_retries: int = 20): + self.n_retries = 0 + self.max_retries = max_retries + + def step(self): + self.n_retries += 1 + + def wait(self): + time.sleep(0.1) + + def is_done(self) -> bool: + return self.n_retries >= self.max_retries + + +class MaxWaitTime(RetryMechanism): + """Check for submissions status every 100 ms and wait for all submissions + a maximum of `max_wait_time` (seconds).""" + + def __init__(self, max_wait_time_sec: float = 5 * 60): + self.max_wait_time_sec = max_wait_time_sec + self.total_wait_time = 0 + + def step(self): + self.total_wait_time += 0.1 + + def wait(self): + time.sleep(0.1) + + def is_done(self): + return self.total_wait_time >= self.max_wait_time_sec + + +class RegularPeriodRetry(RetryMechanism): + """Check for submissions status periodically for indefinite amount of time.""" + + def __init__(self, wait_time_sec: float = 0.1): + self.wait_time_sec = wait_time_sec + + def step(self): + pass + + def wait(self): + time.sleep(self.wait_time_sec) + + def is_done(self) -> bool: + return False diff --git a/src/judge0/submission.py b/src/judge0/submission.py index 82d5ab7..47c77b4 100644 --- a/src/judge0/submission.py +++ b/src/judge0/submission.py @@ -1,5 +1,7 @@ from base64 import b64decode, b64encode +from .common import Status + ENCODED_REQUEST_FIELDS = { "source_code", @@ -146,3 +148,9 @@ def to_dict(self) -> dict: body[field] = value return body + + def is_done(self) -> bool: + if self.status is None: + return False + else: + return self.status not in [Status.IN_QUEUE, Status.ACCEPTED]