Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ The task context has the following attributes:

- `task_result`: The running task result
- `attempt`: The current attempt number for the task
- `metadata`: A `dict` which can be used to write arbitrary [metadata](#metadata). If a backend doesn't support metadata, this dictionary will always be empty. Keys starting `_django_tasks` should be reserved for backend implementations.
- `metadata`: A `dict` which can be used to write arbitrary [metadata](#metadata). If a backend doesn't support metadata, this dictionary will always be empty. Keys starting `_django_tasks` should be reserved for backend implementations.

And the following methods:

Expand Down Expand Up @@ -209,10 +209,10 @@ default_task_backend.get_result(result_id)

### Return values

If your task returns something, it can be retrieved from the `.return_value` attribute on a `TaskResult`. Accessing this property on an unsuccessful task (ie not `SUCCEEDED`) will raise a `ValueError`.
If your task returns something, it can be retrieved from the `.return_value` attribute on a `TaskResult`. Accessing this property on an unsuccessful task (ie not `SUCCESSFUL`) will raise a `ValueError`.

```python
assert result.status == TaskResultStatus.SUCCEEDED
assert result.status == TaskResultStatus.SUCCESSFUL
assert result.return_value == 42
```

Expand All @@ -221,7 +221,7 @@ If a result has been updated in the background, you can call `refresh` on it to
```python
assert result.status == TaskResultStatus.READY
result.refresh()
assert result.status == TaskResultStatus.SUCCEEDED
assert result.status == TaskResultStatus.SUCCESSFUL
```

#### Errors
Expand Down Expand Up @@ -252,7 +252,7 @@ Attached to a task result is "metadata". This metadata can be used as a space to

During a task, metadata can be accessed from `context.metadata`, and `result.metadata` from retrieved results.

Metadata is saved when a task is finished, regardless of whether it succeeded or failed. Additionally, metadata can be saved manually using `context.save_metadata`. If a backend doesn't support metadata, this method will raise an exception.
Metadata is saved when a task is finished, regardless of whether it was successful or failed. Additionally, metadata can be saved manually using `context.save_metadata`. If a backend doesn't support metadata, this method will raise an exception.

### Backend introspecting

Expand All @@ -279,7 +279,7 @@ A few [Signals](https://docs.djangoproject.com/en/stable/topics/signals/) are pr
Whilst signals are available, they may not be the most maintainable approach.

- `django_tasks.signals.task_enqueued`: Called when a task is enqueued. The sender is the backend class. Also called with the enqueued `task_result`.
- `django_tasks.signals.task_finished`: Called when a task finishes (`SUCCEEDED` or `FAILED`). The sender is the backend class. Also called with the finished `task_result`.
- `django_tasks.signals.task_finished`: Called when a task finishes (`SUCCESSFUL` or `FAILED`). The sender is the backend class. Also called with the finished `task_result`.
- `django_tasks.signals.task_started`: Called immediately before a task starts executing. The sender is the backend class. Also called with the started `task_result`.

## RQ
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def run(self) -> None:

def run_task(self, db_task_result: DBTaskResult) -> None:
"""
Run the given task, marking it as succeeded or failed.
Run the given task, marking it as successful or failed.
"""
try:
self.running_task = True
Expand All @@ -170,7 +170,7 @@ def run_task(self, db_task_result: DBTaskResult) -> None:

# Setting the return and success value inside the error handling,
# So errors setting it (eg JSON encode) can still be recorded
db_task_result.set_succeeded(return_value, task_result.metadata)
db_task_result.set_successful(return_value, task_result.metadata)
task_finished.send(
sender=backend_type, task_result=db_task_result.task_result
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def handle(
results = results.filter(finished_at__lte=min_age)
else:
results = results.filter(
Q(status=TaskResultStatus.SUCCEEDED, finished_at__lte=min_age)
Q(status=TaskResultStatus.SUCCESSFUL, finished_at__lte=min_age)
| Q(status=TaskResultStatus.FAILED, finished_at__lte=failed_min_age)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.migrations.state import StateApps

from django_tasks import TaskResultStatus


def separate_results_field(
apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
Expand All @@ -14,12 +12,12 @@ def separate_results_field(

# If a task succeeded, the result is its return value
DBTaskResult.objects.using(schema_editor.connection.alias).filter(
status=TaskResultStatus.SUCCEEDED
status="SUCCEEDED"
).update(return_value=models.F("result"))

# If a task failed, the result is the exception data (or nothing)
DBTaskResult.objects.using(schema_editor.connection.alias).filter(
status=TaskResultStatus.FAILED
status="FAILED"
).update(exception_data=models.F("result"))


Expand All @@ -30,12 +28,12 @@ def merge_results_field(

# If a task succeeded, the result is its return value
DBTaskResult.objects.using(schema_editor.connection.alias).filter(
status=TaskResultStatus.SUCCEEDED
status="SUCCEEDED"
).update(result=models.F("return_value"))

# If a task failed, the result is the exception data (or nothing)
DBTaskResult.objects.using(schema_editor.connection.alias).filter(
status=TaskResultStatus.FAILED
status="FAILED"
).update(result=models.F("exception_data"))


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.migrations.state import StateApps

from django_tasks import TaskResultStatus


def separate_results_field(
apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
Expand All @@ -14,7 +12,7 @@ def separate_results_field(

DBTaskResult.objects.using(schema_editor.connection.alias).filter(
status="COMPLETE"
).update(status=TaskResultStatus.SUCCEEDED)
).update(status="SUCCEEDED")


def merge_results_field(
Expand All @@ -23,7 +21,7 @@ def merge_results_field(
DBTaskResult = apps.get_model("django_tasks_database", "DBTaskResult")

DBTaskResult.objects.using(schema_editor.connection.alias).filter(
status=TaskResultStatus.SUCCEEDED
status="SUCCEEDED"
).update(status="COMPLETE")


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 6.0 on 2026-01-09

from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.migrations.state import StateApps


def forwards(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None:
DBTaskResult = apps.get_model("django_tasks_database", "DBTaskResult")
DBTaskResult.objects.using(schema_editor.connection.alias).filter(
status="SUCCEEDED"
).update(status="SUCCESSFUL")


def backwards(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None:
DBTaskResult = apps.get_model("django_tasks_database", "DBTaskResult")
DBTaskResult.objects.using(schema_editor.connection.alias).filter(
status="SUCCESSFUL"
).update(status="SUCCEEDED")


class Migration(migrations.Migration):
dependencies = [
("django_tasks_database", "0017_dbtaskresult_metadata"),
]

operations = [
migrations.AlterField(
model_name="dbtaskresult",
name="status",
field=models.CharField(
choices=[
("READY", "Ready"),
("RUNNING", "Running"),
("FAILED", "Failed"),
("SUCCESSFUL", "Successful"),
],
default="READY",
max_length=10,
verbose_name="status",
),
),
migrations.RunPython(forwards, backwards),
]
10 changes: 5 additions & 5 deletions django_tasks/backends/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ def ready(self) -> "DBTaskResultQuerySet":
models.Q(run_after=get_date_max()) | models.Q(run_after__lte=timezone.now())
)

def succeeded(self) -> "DBTaskResultQuerySet":
return self.filter(status=TaskResultStatus.SUCCEEDED)
def successful(self) -> "DBTaskResultQuerySet":
return self.filter(status=TaskResultStatus.SUCCESSFUL)

def failed(self) -> "DBTaskResultQuerySet":
return self.filter(status=TaskResultStatus.FAILED)
Expand All @@ -82,7 +82,7 @@ def running(self) -> "DBTaskResultQuerySet":
return self.filter(status=TaskResultStatus.RUNNING)

def finished(self) -> "DBTaskResultQuerySet":
return self.failed() | self.succeeded()
return self.failed() | self.successful()

@retry()
def get_locked(self) -> Optional["DBTaskResult"]:
Expand Down Expand Up @@ -233,8 +233,8 @@ def claim(self, worker_id: str) -> None:
self.save(update_fields=["status", "started_at", "worker_ids"])

@retry()
def set_succeeded(self, return_value: Any, metadata: dict) -> None:
self.status = TaskResultStatus.SUCCEEDED
def set_successful(self, return_value: Any, metadata: dict) -> None:
self.status = TaskResultStatus.SUCCESSFUL
self.finished_at = timezone.now()
self.return_value = return_value
self.exception_class_path = ""
Expand Down
2 changes: 1 addition & 1 deletion django_tasks/backends/immediate.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def _execute_task(self, task_result: TaskResult) -> None:
task_finished.send(type(self), task_result=task_result)
else:
object.__setattr__(task_result, "finished_at", timezone.now())
object.__setattr__(task_result, "status", TaskResultStatus.SUCCEEDED)
object.__setattr__(task_result, "status", TaskResultStatus.SUCCESSFUL)

task_finished.send(type(self), task_result=task_result)

Expand Down
4 changes: 2 additions & 2 deletions django_tasks/backends/rq.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

RQ_STATUS_TO_RESULT_STATUS = {
JobStatus.QUEUED: TaskResultStatus.READY,
JobStatus.FINISHED: TaskResultStatus.SUCCEEDED,
JobStatus.FINISHED: TaskResultStatus.SUCCESSFUL,
JobStatus.FAILED: TaskResultStatus.FAILED,
JobStatus.STARTED: TaskResultStatus.RUNNING,
JobStatus.DEFERRED: TaskResultStatus.READY,
Expand Down Expand Up @@ -194,7 +194,7 @@ def success_callback(job: Job, connection: Redis | None, result: Any) -> None:

task_result = job.task_result

object.__setattr__(task_result, "status", TaskResultStatus.SUCCEEDED)
object.__setattr__(task_result, "status", TaskResultStatus.SUCCESSFUL)

task_finished.send(type(task_result.task.get_backend()), task_result=task_result)

Expand Down
6 changes: 3 additions & 3 deletions django_tasks/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class TaskResultStatus(TextChoices):
FAILED = ("FAILED", pgettext_lazy("Task", "Failed"))
"""The Task raised an exception during execution, or was unable to start."""

SUCCEEDED = ("SUCCEEDED", pgettext_lazy("Task", "Succeeded"))
SUCCESSFUL = ("SUCCESSFUL", pgettext_lazy("Task", "Successful"))
"""The Task has finished running successfully."""


Expand Down Expand Up @@ -324,7 +324,7 @@ def return_value(self) -> T | None:
If the task didn't succeed, an exception is raised.
This is to distinguish against the task returning None.
"""
if self.status == TaskResultStatus.SUCCEEDED:
if self.status == TaskResultStatus.SUCCESSFUL:
return cast(T, self._return_value)
elif self.status == TaskResultStatus.FAILED:
raise ValueError("Task failed")
Expand All @@ -334,7 +334,7 @@ def return_value(self) -> T | None:
@property
def is_finished(self) -> bool:
"""Has the task finished?"""
return self.status in {TaskResultStatus.FAILED, TaskResultStatus.SUCCEEDED}
return self.status in {TaskResultStatus.FAILED, TaskResultStatus.SUCCESSFUL}

@property
def attempts(self) -> int:
Expand Down
Loading