Skip to content

Commit

Permalink
Clarify docs slightly on revoked behavior, clean up code.
Browse files Browse the repository at this point in the history
Fixes #784
  • Loading branch information
coleifer committed Jan 11, 2024
1 parent 1653f92 commit 922b74e
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 1 deletion.
19 changes: 19 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,25 @@ Huey object

.. py:method:: is_revoked(task, timestamp=None)
:param task: either a task instance, a task ID, a Result, or a Task class.

This method should rarely need to be called directly. Typically you
should rather use the ``is_revoked`` method on the object that is being
revoked, for example:

.. code-block:: python
@huey.task()
def greet(name):
return 'Hello %s' % name
r = greet.schedule(delay=60, args=('Huey',))
r.revoke() # Revoke this task.
r.is_revoked() # True.
greet.revoke() # Revoke ALL invocations of this task.
greet.is_revoked() # True.
.. seealso::
For task instances, use :py:meth:`Result.is_revoked`.

Expand Down
11 changes: 10 additions & 1 deletion huey/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,11 +514,15 @@ def _task_key(self, task_class, key):
return ':'.join((key, self._registry.task_to_string(task_class)))

def revoke_all(self, task_class, revoke_until=None, revoke_once=False):
if isinstance(task_class, TaskWrapper):
task_class = task_class.task_class
if revoke_until is not None:
revoke_until = normalize_time(revoke_until, utc=self.utc)
self.put(self._task_key(task_class, 'rt'), (revoke_until, revoke_once))

def restore_all(self, task_class):
if isinstance(task_class, TaskWrapper):
task_class = task_class.task_class
return self.delete(self._task_key(task_class, 'rt'))

def revoke(self, task, revoke_until=None, revoke_once=False):
Expand Down Expand Up @@ -563,14 +567,18 @@ def _check_revoked(self, revoke_id, timestamp=None, peek=True):
return True, False

def is_revoked(self, task, timestamp=None, peek=True):
if isinstance(task, TaskWrapper):
task = task.task_class
if inspect.isclass(task) and issubclass(task, Task):
key = self._task_key(task, 'rt')
is_revoked, can_restore = self._check_revoked(key, timestamp, peek)
if can_restore:
self.restore_all(task)
return is_revoked

if not isinstance(task, Task):
if isinstance(task, Result):
task = task.task
elif not isinstance(task, Task):
# Assume we've been given a task ID.
task = Task(id=task)

Expand Down Expand Up @@ -951,6 +959,7 @@ def my_task(a, b):
def __init__(self, huey, task):
self.huey = huey
self.task = task
self.revoke_id = task.revoke_id
self._result = EmptyData

def __repr__(self):
Expand Down
9 changes: 9 additions & 0 deletions huey/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ def task_a(n):
# The result-wrapper will indicate the tasks are revoked.
for r in (r1, r2, r3):
self.assertTrue(r.is_revoked())
self.assertTrue(self.huey.is_revoked(r))
# We don't have the task class when using an ID so this doesn't
# work.
self.assertFalse(self.huey.is_revoked(r.task.id))

# Task is discarded and not executed, due to being revoked.
t1 = self.huey.dequeue()
Expand Down Expand Up @@ -218,6 +222,11 @@ def task_a(n):
self.assertFalse(r2.is_revoked())
self.assertTrue(r3.is_revoked())

self.assertTrue(self.huey.is_revoked(r1))
self.assertTrue(self.huey.is_revoked(r1.task.id))
self.assertFalse(self.huey.is_revoked(r2))
self.assertFalse(self.huey.is_revoked(r2.task.id))

# Task is discarded and not executed, due to being revoked.
t1 = self.huey.dequeue()
self.assertTrue(self.huey.execute(t1) is None)
Expand Down

0 comments on commit 922b74e

Please sign in to comment.