Plain is headed towards 1.0! Subscribe for development updates →

 1class DeferJob(Exception):
 2    """Signal that a job should be deferred and re-tried later.
 3
 4    Unlike regular exceptions that indicate errors, DeferJob is used for expected
 5    delays like:
 6    - Waiting for external resources (API rate limits, data not ready)
 7    - Polling for status changes
 8    - Temporary unavailability
 9
10    Example:
11        # Finite retries - will fail if data never becomes ready
12        if not data.is_ready():
13            raise DeferJob(delay=60, increment_retries=True)
14
15        # Infinite retries - safe for rate limits
16        if rate_limited():
17            raise DeferJob(delay=300, increment_retries=False)
18    """
19
20    def __init__(self, *, delay: int, increment_retries: bool = False):
21        self.delay = delay
22        self.increment_retries = increment_retries
23        super().__init__(f"Job deferred for {delay} seconds")
24
25
26class DeferError(Exception):
27    """Raised when a deferred job cannot be re-enqueued.
28
29    This typically happens when concurrency limits prevent the job from being
30    re-queued. The transaction will be rolled back and the job will remain
31    in its current state, then be converted to ERRORED status for retry.
32    """
33
34    pass