django-qstash 0.0.7__py3-none-any.whl → 0.0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of django-qstash might be problematic. Click here for more details.

django_qstash/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.0.7"
3
+ __version__ = "0.0.8"
4
4
 
5
- from .tasks import shared_task
5
+ from django_qstash.app import shared_task
6
6
 
7
7
  __all__ = ["shared_task"]
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ from .base import AsyncResult
4
+ from .base import QStashTask
5
+ from .decorators import shared_task
6
+
7
+ __all__ = ["AsyncResult", "QStashTask", "shared_task"]
@@ -118,26 +118,3 @@ class AsyncResult:
118
118
  @property
119
119
  def id(self) -> str:
120
120
  return self.task_id
121
-
122
-
123
- def shared_task(
124
- func: Callable | None = None,
125
- name: str | None = None,
126
- deduplicated: bool = False,
127
- **options: dict[str, Any],
128
- ) -> QStashTask:
129
- """
130
- Decorator that mimics Celery's shared_task
131
-
132
- Can be used as:
133
- @shared_task
134
- def my_task():
135
- pass
136
-
137
- @shared_task(name="custom_name", deduplicated=True)
138
- def my_task():
139
- pass
140
- """
141
- if func is not None:
142
- return QStashTask(func, name=name, deduplicated=deduplicated, **options)
143
- return lambda f: QStashTask(f, name=name, deduplicated=deduplicated, **options)
@@ -0,0 +1,29 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+ from typing import Callable
5
+
6
+ from django_qstash.app.base import QStashTask
7
+
8
+
9
+ def shared_task(
10
+ func: Callable | None = None,
11
+ name: str | None = None,
12
+ deduplicated: bool = False,
13
+ **options: dict[str, Any],
14
+ ) -> QStashTask:
15
+ """
16
+ Decorator that mimics Celery's shared_task
17
+
18
+ Can be used as:
19
+ @shared_task
20
+ def my_task():
21
+ pass
22
+
23
+ @shared_task(name="custom_name", deduplicated=True)
24
+ def my_task():
25
+ pass
26
+ """
27
+ if func is not None:
28
+ return QStashTask(func, name=name, deduplicated=deduplicated, **options)
29
+ return lambda f: QStashTask(f, name=name, deduplicated=deduplicated, **options)
@@ -32,7 +32,7 @@ def discover_tasks() -> list[tuple[str, str]]:
32
32
  ('other_app.tasks.custom_task', 'special_name')
33
33
  ]
34
34
  """
35
- from django_qstash.tasks import QStashTask
35
+ from django_qstash.app import QStashTask
36
36
 
37
37
  discovered_tasks = []
38
38
  packages = []
@@ -71,7 +71,7 @@ def discover_tasks() -> list[tuple[str, str]]:
71
71
  if attr.name == attr_name:
72
72
  label = value
73
73
  else:
74
- label = f"{attr.name} ({value})"
74
+ label = f"{attr.name} ({package}.tasks)"
75
75
  discovered_tasks.append((value, label))
76
76
  except Exception as e:
77
77
  warnings.warn(
@@ -1,11 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
- from datetime import timedelta
4
-
5
- from django.apps import apps
6
3
  from django.conf import settings
7
4
  from django.core.management.base import BaseCommand
8
- from django.utils import timezone
5
+
6
+ from django_qstash.results.tasks import clear_stale_results_task
9
7
 
10
8
  DJANGO_QSTASH_RESULT_TTL = getattr(settings, "DJANGO_QSTASH_RESULT_TTL", 604800)
11
9
 
@@ -25,37 +23,20 @@ class Command(BaseCommand):
25
23
  type=int,
26
24
  help="The number of seconds ago to clear results for",
27
25
  )
26
+ parser.add_argument(
27
+ "--delay", action="store_true", help="Offload request using django_qstash"
28
+ )
28
29
 
29
30
  def handle(self, *args, **options):
31
+ delay = options["delay"]
30
32
  no_input = options["no_input"]
31
33
  since = options.get("since") or DJANGO_QSTASH_RESULT_TTL
32
- cutoff_date = timezone.now() - timedelta(seconds=since)
33
- try:
34
- TaskResult = apps.get_model("django_qstash_results", "TaskResult")
35
- except LookupError:
36
- self.stdout.write(
37
- self.style.ERROR(
38
- "Django QStash Results not installed.\nAdd `django_qstash.results` to INSTALLED_APPS and run migrations."
39
- )
34
+ user_confirm = not no_input
35
+ if not delay:
36
+ clear_stale_results_task(
37
+ since=since, user_confirm=user_confirm, stdout=self.stdout
38
+ )
39
+ else:
40
+ clear_stale_results_task.delay(
41
+ since=since, user_confirm=user_confirm, stdout=self.stdout
40
42
  )
41
- return
42
- to_delete = TaskResult.objects.filter(date_done__lt=cutoff_date)
43
-
44
- if not to_delete.exists():
45
- self.stdout.write("No stale Django QStash task results found")
46
- return
47
-
48
- # use input to confirm deletion
49
- self.stdout.write(
50
- f"Deleting {to_delete.count()} task results older than {cutoff_date} ({DJANGO_QSTASH_RESULT_TTL} seconds)"
51
- )
52
- if not no_input:
53
- if input("Are you sure? (y/n): ") != "y":
54
- self.stdout.write("Skipping deletion")
55
- return
56
-
57
- deleted_count, _ = to_delete.delete()
58
-
59
- self.stdout.write(
60
- self.style.SUCCESS(f"Successfully deleted {deleted_count} stale results.")
61
- )
@@ -0,0 +1,67 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from datetime import timedelta
5
+
6
+ from django.apps import apps
7
+ from django.conf import settings
8
+ from django.utils import timezone
9
+
10
+ from django_qstash import shared_task
11
+
12
+ DJANGO_QSTASH_RESULT_TTL = getattr(settings, "DJANGO_QSTASH_RESULT_TTL", 604800)
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ @shared_task(name="Cleanup Task Results")
18
+ def clear_stale_results_task(
19
+ since=None, stdout=None, user_confirm=False, *args, **options
20
+ ):
21
+ delta_seconds = since or DJANGO_QSTASH_RESULT_TTL
22
+ cutoff_date = timezone.now() - timedelta(seconds=delta_seconds)
23
+ TaskResult = None
24
+ try:
25
+ TaskResult = apps.get_model("django_qstash_results", "TaskResult")
26
+ except LookupError as e:
27
+ msg = "Django QStash Results not installed.\nAdd `django_qstash.results` to INSTALLED_APPS and run migrations."
28
+ if stdout is not None:
29
+ stdout.write(msg)
30
+ logger.exception(msg)
31
+ raise e
32
+ qs_to_delete = TaskResult.objects.filter(date_done__lt=cutoff_date)
33
+
34
+ if user_confirm:
35
+ user_input = input("Are you sure? (Y/n): ")
36
+ if f"{user_input}".lower() != "y":
37
+ msg = "Skipping deletion"
38
+ if stdout is not None:
39
+ stdout.write(msg)
40
+ logger.info(msg)
41
+ return
42
+
43
+ if not qs_to_delete.exists():
44
+ msg = "No stale Django QStash task results found"
45
+ if stdout is not None:
46
+ stdout.write(msg)
47
+ else:
48
+ logger.info(msg)
49
+ return
50
+ delete_msg = f"Deleting {qs_to_delete.count()} task results older than {cutoff_date} ({DJANGO_QSTASH_RESULT_TTL} seconds)"
51
+ if stdout is not None:
52
+ stdout.write(delete_msg)
53
+ else:
54
+ logger.info(delete_msg)
55
+ try:
56
+ deleted_count, _ = qs_to_delete.delete()
57
+ msg = f"Successfully deleted {deleted_count} stale results."
58
+ if stdout is not None:
59
+ stdout.write(msg)
60
+ else:
61
+ logger.info(msg)
62
+ except Exception as e:
63
+ msg = f"Error deleting stale results: {e}"
64
+ if stdout is not None:
65
+ stdout.write(msg)
66
+ logger.exception(msg)
67
+ raise e
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-qstash
3
- Version: 0.0.7
3
+ Version: 0.0.8
4
4
  Summary: A drop-in replacement for Celery's shared_task with Upstash QStash.
5
5
  Author-email: Justin Mitchel <justin@codingforentrepreneurs.com>
6
6
  Project-URL: Changelog, https://github.com/jmitchel3/django-qstash
@@ -1,26 +1,29 @@
1
- django_qstash/__init__.py,sha256=y677U8dn62nPF5Er1ROJB-qzlukk7PqiCT2_7iL4osg,117
1
+ django_qstash/__init__.py,sha256=NkydB5VW3zGO7c9-nveE0LELDPNix3lLQIZxWDeFBtI,128
2
2
  django_qstash/callbacks.py,sha256=VG5tGdNzAmUEh7NlpghrxhWvnpRNXZucWmWwxaemw0M,530
3
3
  django_qstash/client.py,sha256=cgHf-g6lDAltY_Vt6GUVJNY2JSz1czBOHL-WVkkLs2M,149
4
4
  django_qstash/exceptions.py,sha256=pH6kKRJFIVFkDHUJQ9yRWmtGdBBSXpNAwMSFuNzMgPw,392
5
5
  django_qstash/handlers.py,sha256=mmm8TJOqV3j1rQXooNOa128gtmALXFNCAaDZ5xwIcuw,4950
6
6
  django_qstash/settings.py,sha256=YvpXMo1AdIWvbotISWJmhg0vrW3A3UQ4BieNzMfRC7Y,524
7
- django_qstash/tasks.py,sha256=VYv7m0Uz1v8kPBegGHam5AH0Hcc-n53BZz3IdQcAqsk,4462
8
7
  django_qstash/utils.py,sha256=wrTU30cobO2di18BNEFtKD4ih2euf7eQNpg6p6TkQ1Y,1185
9
8
  django_qstash/views.py,sha256=H32f_jGnlwOTO0YG9znNo2b-GRYZ8TM-Wt0T62SGdXM,639
9
+ django_qstash/app/__init__.py,sha256=353w1JyvIinkr3aHjyT7I01utFM56lrgIjSSfqtJkA4,187
10
+ django_qstash/app/base.py,sha256=gM7GIJh_omZcxbmsrwAEadA-N6EuUJbPzh0CflOIVRg,3864
11
+ django_qstash/app/decorators.py,sha256=Gn0TAxUHfS4fKUdKdArvHeWlxrRvj9_NOVnC1a6pGTQ,732
10
12
  django_qstash/discovery/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
13
  django_qstash/discovery/fields.py,sha256=qZDKMpl6VMRJL0FkGwXkeN_rcCT32cupDaXJOz-bFzs,1226
12
14
  django_qstash/discovery/models.py,sha256=9ml9lTKEqEKx2uqYvejZw_BjdnowgFOPE7rYNt_8E9A,685
13
- django_qstash/discovery/utils.py,sha256=k-QfOGElehCM7tV5v0FJAfwKqJWjez4xFf2RUyxIgP0,3218
15
+ django_qstash/discovery/utils.py,sha256=NxX6Y-Hd_AALgeESUW8AbIHReYPpbntvZjhlbrXTYnw,3224
14
16
  django_qstash/discovery/validators.py,sha256=NNCf7ltW--sTw0w8FWwTp-4PtiS35U6DITEApx-D7X4,645
15
17
  django_qstash/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
18
  django_qstash/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- django_qstash/management/commands/clear_stale_results.py,sha256=stHCnvC1ER_rZXKUK-YVUgazC2q04eGIHjo_BrPSDEI,2096
19
+ django_qstash/management/commands/clear_stale_results.py,sha256=mxXXqIy6pnvsN8JVE0xe3mypqtkaZbpqdBjpox-MDik,1402
18
20
  django_qstash/management/commands/task_schedules.py,sha256=b9lJ1vjQKHyGzWAo9csGwE_oaKfgcSC8bPFLt9Ry6WE,4278
19
21
  django_qstash/results/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
22
  django_qstash/results/admin.py,sha256=q9fn3lfn0gviMfiimYij0wBCYww7FxyrOfGPr1NvntA,434
21
23
  django_qstash/results/apps.py,sha256=4me4cg5yeoeSJTphkHYzGMJUfGucT47FNIUMYu5gmIo,275
22
24
  django_qstash/results/models.py,sha256=aEiAhGJOuLRtjibUw6xdQqUt3eYKLqY2as4I4QSrF5U,1047
23
25
  django_qstash/results/services.py,sha256=HvNp5D1tQ__nz4LVUTAGxuyLl_dnlBps4pJ6E9HD2kA,991
26
+ django_qstash/results/tasks.py,sha256=NETuiREwCKfajWKCnnB5iAsHoSsvBIThf805_wpzjbw,2166
24
27
  django_qstash/results/migrations/0001_initial.py,sha256=A90SKgWmBf4SIJYG1Jh6-b_81Ia1zIzGj3Bfl1O4-kg,1902
25
28
  django_qstash/results/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
29
  django_qstash/schedules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -36,7 +39,7 @@ django_qstash/schedules/validators.py,sha256=i8IEjnRVk-iysmqvT_kbPYpxTKCQWoX9P1J
36
39
  django_qstash/schedules/migrations/0001_initial.py,sha256=66cA8xnJV3h7QgzCaOiv-Nu3Xl9IdZQPgQKhxyW3bs4,4516
37
40
  django_qstash/schedules/migrations/0002_taskschedule_updated_at.py,sha256=6hZO0a9P2ZpOROkk7O5UXBhahghU0QfxZl4E-c3HKGw,459
38
41
  django_qstash/schedules/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
- django_qstash-0.0.7.dist-info/METADATA,sha256=VXoUQawPhDe9DL1H6D1RxonOPVzzG-yGS1gmfWLjM0Q,12307
40
- django_qstash-0.0.7.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
41
- django_qstash-0.0.7.dist-info/top_level.txt,sha256=AlV3WSK1A0ZvKuCLsINtIJhJW8zo7SEB-D3_RAjZ0hI,14
42
- django_qstash-0.0.7.dist-info/RECORD,,
42
+ django_qstash-0.0.8.dist-info/METADATA,sha256=bK9_Xyk6YmMJZO1FF3L3mZTuOlXkUIU7azMroDV6IQY,12307
43
+ django_qstash-0.0.8.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
44
+ django_qstash-0.0.8.dist-info/top_level.txt,sha256=AlV3WSK1A0ZvKuCLsINtIJhJW8zo7SEB-D3_RAjZ0hI,14
45
+ django_qstash-0.0.8.dist-info/RECORD,,