<commit_before>"""
=========================
Cancelable tasks overview
=========================

For long-running :class:`Task`'s, it can be desirable to support
aborting during execution. Of course, these tasks should be built to
support abortion specifically.

The :class:`CancelableTask` serves as a base class for all :class:`Task`
objects that should support cancellation by producers.

* Producers may invoke the :meth:`cancel` method on
  :class:`CancelableAsyncResult` instances, to request abortion.

* Consumers (workers) should periodically check (and honor!) the
  :meth:`is_cancelled` method at controlled points in their task's
  :meth:`run` method. The more often, the better.

The necessary intermediate communication is dealt with by the
:class:`CancelableTask` implementation.

Usage example
-------------

In the consumer:

.. code-block:: python

   from celery.contrib.cancelable import CancelableTask
   def MyLongRunningTask(CancelableTask):
       def run(self, **kwargs):
           logger = self.get_logger()
           results = []
           for x in xrange(100):
               # Check after every 5 loops..
               if x % 5 == 0:  # alternatively, check when some timer is due
                   if self.is_cancelled(**kwargs):
                       # Respect the cancelled status and terminate
                       # gracefully
                       logger.warning('Task cancelled.')
                       return None
               y = do_something_expensive(x)
               results.append(y)
           logger.info('Task finished.')
           return results


In the producer:

.. code-block:: python

   from myproject.tasks import MyLongRunningTask
   def myview(request):
       async_result = MyLongRunningTask.delay()
       # async_result is of type CancelableAsyncResult

       # After 10 seconds, cancel the task
       time.sleep(10)
       async_result.cancel()

       ...

After the `async_result.cancel()` call, the task execution is not
aborted immediately. In fact, it is not guaranteed to abort at all. Keep
checking the `async_result` status, or call `async_result.wait()` to
have it block until the task is finished.

"""

from celery.task.base import Task
from celery.result import AsyncResult
from multiprocessing import Process, Event

""" Task States

.. data:: CANCELLED

    Task is cancelled (typically by the producer) and should be
    cancelled as soon as possible.

"""
CANCELLED = "CANCELLED"

class CancelableAsyncResult(AsyncResult):
    """Represents a cancelable result.

    Specifically, this gives the AsyncResult a cancel() method, which sets
    the state of the underlying Task to "CANCELLED".

    """

    def is_cancelled(self):
        """Returns ``True'' if the task is (being) cancelled."""
        return self.backend.get_status(self.task_id) == CANCELLED

    def cancel(self):
        """Set the state of the task to cancelled.

        TODO: Be more descriptive. What does this mean for the worker?
        TODO: What does the method return?

        """<commit_msg>Filled in the TODO gaps in the documentation for CancelableAsyncResult.<commit_after>"""
=========================
Cancelable tasks overview
=========================

For long-running :class:`Task`'s, it can be desirable to support
aborting during execution. Of course, these tasks should be built to
support abortion specifically.

The :class:`CancelableTask` serves as a base class for all :class:`Task`
objects that should support cancellation by producers.

* Producers may invoke the :meth:`cancel` method on
  :class:`CancelableAsyncResult` instances, to request abortion.

* Consumers (workers) should periodically check (and honor!) the
  :meth:`is_cancelled` method at controlled points in their task's
  :meth:`run` method. The more often, the better.

The necessary intermediate communication is dealt with by the
:class:`CancelableTask` implementation.

Usage example
-------------

In the consumer:

.. code-block:: python

   from celery.contrib.cancelable import CancelableTask
   def MyLongRunningTask(CancelableTask):
       def run(self, **kwargs):
           logger = self.get_logger()
           results = []
           for x in xrange(100):
               # Check after every 5 loops..
               if x % 5 == 0:  # alternatively, check when some timer is due
                   if self.is_cancelled(**kwargs):
                       # Respect the cancelled status and terminate
                       # gracefully
                       logger.warning('Task cancelled.')
                       return None
               y = do_something_expensive(x)
               results.append(y)
           logger.info('Task finished.')
           return results


In the producer:

.. code-block:: python

   from myproject.tasks import MyLongRunningTask
   def myview(request):
       async_result = MyLongRunningTask.delay()
       # async_result is of type CancelableAsyncResult

       # After 10 seconds, cancel the task
       time.sleep(10)
       async_result.cancel()

       ...

After the `async_result.cancel()` call, the task execution is not
aborted immediately. In fact, it is not guaranteed to abort at all. Keep
checking the `async_result` status, or call `async_result.wait()` to
have it block until the task is finished.

"""

from celery.task.base import Task
from celery.result import AsyncResult
from multiprocessing import Process, Event

""" Task States

.. data:: CANCELLED

    Task is cancelled (typically by the producer) and should be
    cancelled as soon as possible.

"""
CANCELLED = "CANCELLED"

class CancelableAsyncResult(AsyncResult):
    """Represents a cancelable result.

    Specifically, this gives the AsyncResult a cancel() method, which sets
    the state of the underlying Task to "CANCELLED".

    """

    def is_cancelled(self):
        """Returns ``True'' if the task is (being) cancelled."""
        return self.backend.get_status(self.task_id) == CANCELLED

    def cancel(self):
        """Set the state of the task to :const:`CANCELLED`.

        Cancelable tasks monitor their state at regular intervals and
        terminate execution if so.

        Be aware that invoking this method does not guarantee when the
        task will be cancelled (or even if the task will be cancelled at
        all).

        """
{'fraction_non_alphanumeric': 0.0970231532524807, 'fraction_numerical': 0.003150102378327296, 'mean_word_length': 2.802395209580838, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7121738', 'n_tokens_mistral': 1687, 'n_tokens_neox': 1591, 'n_words': 652}