django-qstash 0.0.9__tar.gz → 0.0.10__tar.gz

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.

Files changed (58) hide show
  1. {django_qstash-0.0.9 → django_qstash-0.0.10}/PKG-INFO +99 -14
  2. {django_qstash-0.0.9 → django_qstash-0.0.10}/README.md +98 -13
  3. {django_qstash-0.0.9 → django_qstash-0.0.10}/pyproject.toml +1 -1
  4. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/__init__.py +1 -1
  5. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/discovery/fields.py +6 -6
  6. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/discovery/utils.py +10 -2
  7. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/discovery/validators.py +2 -2
  8. django_qstash-0.0.10/src/django_qstash/management/commands/available_tasks.py +37 -0
  9. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash.egg-info/PKG-INFO +99 -14
  10. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash.egg-info/SOURCES.txt +1 -0
  11. {django_qstash-0.0.9 → django_qstash-0.0.10}/setup.cfg +0 -0
  12. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/app/__init__.py +0 -0
  13. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/app/base.py +0 -0
  14. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/app/decorators.py +0 -0
  15. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/callbacks.py +0 -0
  16. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/client.py +0 -0
  17. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/discovery/__init__.py +0 -0
  18. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/discovery/models.py +0 -0
  19. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/exceptions.py +0 -0
  20. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/handlers.py +0 -0
  21. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/management/__init__.py +0 -0
  22. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/management/commands/__init__.py +0 -0
  23. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/management/commands/clear_stale_results.py +0 -0
  24. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/management/commands/task_schedules.py +0 -0
  25. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/results/__init__.py +0 -0
  26. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/results/admin.py +0 -0
  27. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/results/apps.py +0 -0
  28. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/results/migrations/0001_initial.py +0 -0
  29. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/results/migrations/__init__.py +0 -0
  30. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/results/models.py +0 -0
  31. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/results/services.py +0 -0
  32. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/results/tasks.py +0 -0
  33. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/__init__.py +0 -0
  34. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/admin.py +0 -0
  35. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/apps.py +0 -0
  36. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/exceptions.py +0 -0
  37. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/formatters.py +0 -0
  38. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/forms.py +0 -0
  39. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/migrations/0001_initial.py +0 -0
  40. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/migrations/0002_taskschedule_updated_at.py +0 -0
  41. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/migrations/__init__.py +0 -0
  42. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/models.py +0 -0
  43. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/services.py +0 -0
  44. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/signals.py +0 -0
  45. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/schedules/validators.py +0 -0
  46. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/settings.py +0 -0
  47. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/utils.py +0 -0
  48. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash/views.py +0 -0
  49. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash.egg-info/dependency_links.txt +0 -0
  50. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash.egg-info/requires.txt +0 -0
  51. {django_qstash-0.0.9 → django_qstash-0.0.10}/src/django_qstash.egg-info/top_level.txt +0 -0
  52. {django_qstash-0.0.9 → django_qstash-0.0.10}/tests/test_callbacks.py +0 -0
  53. {django_qstash-0.0.9 → django_qstash-0.0.10}/tests/test_exceptions.py +0 -0
  54. {django_qstash-0.0.9 → django_qstash-0.0.10}/tests/test_handlers.py +0 -0
  55. {django_qstash-0.0.9 → django_qstash-0.0.10}/tests/test_results_models.py +0 -0
  56. {django_qstash-0.0.9 → django_qstash-0.0.10}/tests/test_settings.py +0 -0
  57. {django_qstash-0.0.9 → django_qstash-0.0.10}/tests/test_utils.py +0 -0
  58. {django_qstash-0.0.9 → django_qstash-0.0.10}/tests/test_views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-qstash
3
- Version: 0.0.9
3
+ Version: 0.0.10
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
@@ -68,8 +68,13 @@ This allows us to:
68
68
  - [`.apply_async()` With Time Delay](#apply_async-with-time-delay)
69
69
  - [JSON-ready Arguments](#json-ready-arguments)
70
70
  - [Example Task](#example-task)
71
- - [Configuration](#configuration)
72
- - [Storing Task Results (Optional)](#storing-task-results-optional)
71
+ - [Management Commands](#management-commands)
72
+ - [Development Usage](#development-usage)
73
+ - [Django Settings Configuration](#django-settings-configuration)
74
+ - [Schedule Tasks (Optional)](#schedule-tasks-optional)
75
+ - [Installation](#installation-1)
76
+ - [Schedule a Task](#schedule-a-task)
77
+ - [Store Task Results (Optional)](#store-task-results-optional)
73
78
  - [Clear Stale Results](#clear-stale-results)
74
79
  - [Definitions](#definitions)
75
80
  - [Motivation](#motivation)
@@ -89,12 +94,13 @@ INSTALLED_APPS = [
89
94
  ##...
90
95
  "django_qstash",
91
96
  "django_qstash.results",
97
+ "django_qstash.schedules",
92
98
  ##...
93
99
  ]
94
100
  ```
95
101
  - `django_qstash` Includes the `@shared_task` decorator and webhook view
96
102
  - `django_qstash.results` (Optional): Store task results in Django DB
97
-
103
+ - `django_qstash.schedules` (Optional): Use QStash Schedules to run your `django_qstash` tasks. Out of the box support for _django_qstash_ `@shared_task`. Schedule tasks using _cron_ (e.g. `0 0 * * *`) format which is required based on [QStash Schedules](https://upstash.com/docs/qstash/features/schedules). use [contrab.guru](https://crontab.guru/) for writing the cron format.
98
104
 
99
105
  ### Configure Webhook URL
100
106
 
@@ -157,7 +163,6 @@ def hello_world(name: str, age: int = None, activity: str = None):
157
163
  print(f"Hello {name}! I see you're {activity} at {age} years old.")
158
164
  ```
159
165
 
160
-
161
166
  ### Regular Task Call
162
167
  Nothing special here. Just call the function like any other to verify it works.
163
168
 
@@ -254,22 +259,101 @@ math_add_task.apply_async(
254
259
  The `.delay()` method does not support a countdown parameter because it simply passes the arguments (*args, **kwargs) to the `apply_async()` method.
255
260
 
256
261
 
257
- ## Configuration
262
+ ## Management Commands
263
+
264
+ - `python manage.py available_tasks` to view all available tasks
265
+
266
+ _Requires `django_qstash.schedules` installed._
267
+ - `python manage.py task_schedules --list` see all schedules relate to the `DJANGO_QSTASH_DOMAIN`
268
+ - `python manage.py task_schedules --sync` sync schedules based on the `DJANGO_QSTASH_DOMAIN` to store in the Django Admin.
269
+
270
+ ## Development Usage
271
+
272
+ django-qstash requires a public domain to work (e.g. `https://djangoqstash.com`). There are many ways to do this, we recommend:
273
+
274
+ - [Cloudflare Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) with a domain name you control.
275
+ - [ngrok](https://ngrok.com/)
276
+
277
+ Once you have a domain name, you can configure the `DJANGO_QSTASH_DOMAIN` setting in your Django settings.
278
+
279
+
280
+ ## Django Settings Configuration
258
281
 
259
282
  In Django settings, you can configure the following:
260
283
 
261
- `DJANGO_QSTASH_DOMAIN`: Must be a valid and publicly accessible domain. For example `https://djangoqstash.com`
284
+ - `DJANGO_QSTASH_DOMAIN`: Must be a valid and publicly accessible domain. For example `https://djangoqstash.com`. Review [Development usage](#development-usage) for setting up a domain name during development.
285
+
286
+ - `DJANGO_QSTASH_WEBHOOK_PATH` (default:`/qstash/webhook/`): The path where QStash will send webhooks to your Django application.
262
287
 
263
- In development mode, we recommend using a tunnel like [Cloudflare Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) with a domain name you control. You can also consider [ngrok](https://ngrok.com/).
288
+ - `DJANGO_QSTASH_FORCE_HTTPS` (default:`True`): Whether to force HTTPS for the webhook.
264
289
 
265
- `DJANGO_QSTASH_WEBHOOK_PATH` (default:`/qstash/webhook/`): The path where QStash will send webhooks to your Django application.
290
+ - `DJANGO_QSTASH_RESULT_TTL` (default:`604800`): A number of seconds after which task result data can be safely deleted. Defaults to 604800 seconds (7 days or 7 * 24 * 60 * 60).
266
291
 
267
- `DJANGO_QSTASH_FORCE_HTTPS` (default:`True`): Whether to force HTTPS for the webhook.
268
292
 
269
- `DJANGO_QSTASH_RESULT_TTL` (default:`604800`): A number of seconds after which task result data can be safely deleted. Defaults to 604800 seconds (7 days or 7 * 24 * 60 * 60).
293
+ ## Schedule Tasks (Optional)
270
294
 
295
+ The `django_qstash.schedules` app schedules tasks using Upstash [QStash Schedules](https://upstash.com/docs/qstash/features/schedules) and the django-qstash `@shared_task` decorator.
271
296
 
272
- ## Storing Task Results (Optional)
297
+ ### Installation
298
+
299
+ Update your `INSTALLED_APPS` setting to include `django_qstash.schedules`.
300
+
301
+ ```python
302
+ INSTALLED_APPS = [
303
+ # ...
304
+ "django_qstash", # required
305
+ "django_qstash.schedules",
306
+ # ...
307
+ ]
308
+ ```
309
+
310
+ Run migrations:
311
+ ```bash
312
+ python manage.py migrate django_qstash_schedules
313
+ ```
314
+
315
+
316
+ ## Schedule a Task
317
+
318
+ Tasks must exist before you can schedule them. Review [Define a Task](#define-a-task) for more information.
319
+
320
+ Here's how you can schedule a task:
321
+ - Django Admin (`/admin/django_qstash_schedules/taskschedule/add/`)
322
+ - Django shell (`python manage.py shell`)
323
+
324
+
325
+
326
+
327
+ ```python
328
+ from django_qstash.schedules.models import TaskSchedule
329
+ from django_qstash.discovery.utils import discover_tasks
330
+
331
+ all_available_tasks = discover_tasks(paths_only=True)
332
+
333
+ desired_task = "django_qstash.results.clear_stale_results_task"
334
+ # or desired_task = "example_app.tasks.my_task"
335
+
336
+ task_to_use = desired_task
337
+ if desired_task not in available_task_locations:
338
+ task_to_use = available_task_locations[0]
339
+
340
+ print(f"Using task: {task_to_use}")
341
+
342
+ TaskSchedule.objects.create(
343
+ name="My Schedule",
344
+ cron="0 0 * * *",
345
+ task_name=task_to_use,
346
+ args=["arg1", "arg2"],
347
+ kwargs={"kwarg1": "value1", "kwarg2": "value2"},
348
+ )
349
+ ```
350
+ - `django_qstash.results.clear_stale_results_task` is a built-in task that `django_qstash.results` provides
351
+ - `args` and `kwargs` are the arguments to pass to the task
352
+ - `cron` is the cron schedule to run the task. Use [contrab.guru](https://crontab.guru/) for writing the cron format.
353
+
354
+
355
+
356
+ ## Store Task Results (Optional)
273
357
 
274
358
  In `django_qstash.results.models` we have the `TaskResult` model class that can be used to track async task results. These entries are created via webhooks.
275
359
 
@@ -278,6 +362,7 @@ To install it, just add `django_qstash.results` to your `INSTALLED_APPS` setting
278
362
  ```python
279
363
  INSTALLED_APPS = [
280
364
  # ...
365
+ "django_qstash",
281
366
  "django_qstash.results",
282
367
  # ...
283
368
  ]
@@ -285,14 +370,14 @@ INSTALLED_APPS = [
285
370
 
286
371
  Run migrations:
287
372
  ```bash
288
- python manage.py migrate
373
+ python manage.py migrate django_qstash_results
289
374
  ```
290
375
 
291
376
  ### Clear Stale Results
292
377
 
293
378
  We recommend purging the `TaskResult` model after a certain amount of time.
294
379
  ```bash
295
- python manage.py clear_stale_results
380
+ python manage.py clear_stale_results --since 604800
296
381
  ```
297
382
  Args:
298
383
  - `--since` is the number of seconds ago to clear results for. Defaults to 604800 seconds (7 days or the `DJANGO_QSTASH_RESULT_TTL` setting).
@@ -39,8 +39,13 @@ This allows us to:
39
39
  - [`.apply_async()` With Time Delay](#apply_async-with-time-delay)
40
40
  - [JSON-ready Arguments](#json-ready-arguments)
41
41
  - [Example Task](#example-task)
42
- - [Configuration](#configuration)
43
- - [Storing Task Results (Optional)](#storing-task-results-optional)
42
+ - [Management Commands](#management-commands)
43
+ - [Development Usage](#development-usage)
44
+ - [Django Settings Configuration](#django-settings-configuration)
45
+ - [Schedule Tasks (Optional)](#schedule-tasks-optional)
46
+ - [Installation](#installation-1)
47
+ - [Schedule a Task](#schedule-a-task)
48
+ - [Store Task Results (Optional)](#store-task-results-optional)
44
49
  - [Clear Stale Results](#clear-stale-results)
45
50
  - [Definitions](#definitions)
46
51
  - [Motivation](#motivation)
@@ -60,12 +65,13 @@ INSTALLED_APPS = [
60
65
  ##...
61
66
  "django_qstash",
62
67
  "django_qstash.results",
68
+ "django_qstash.schedules",
63
69
  ##...
64
70
  ]
65
71
  ```
66
72
  - `django_qstash` Includes the `@shared_task` decorator and webhook view
67
73
  - `django_qstash.results` (Optional): Store task results in Django DB
68
-
74
+ - `django_qstash.schedules` (Optional): Use QStash Schedules to run your `django_qstash` tasks. Out of the box support for _django_qstash_ `@shared_task`. Schedule tasks using _cron_ (e.g. `0 0 * * *`) format which is required based on [QStash Schedules](https://upstash.com/docs/qstash/features/schedules). use [contrab.guru](https://crontab.guru/) for writing the cron format.
69
75
 
70
76
  ### Configure Webhook URL
71
77
 
@@ -128,7 +134,6 @@ def hello_world(name: str, age: int = None, activity: str = None):
128
134
  print(f"Hello {name}! I see you're {activity} at {age} years old.")
129
135
  ```
130
136
 
131
-
132
137
  ### Regular Task Call
133
138
  Nothing special here. Just call the function like any other to verify it works.
134
139
 
@@ -225,22 +230,101 @@ math_add_task.apply_async(
225
230
  The `.delay()` method does not support a countdown parameter because it simply passes the arguments (*args, **kwargs) to the `apply_async()` method.
226
231
 
227
232
 
228
- ## Configuration
233
+ ## Management Commands
234
+
235
+ - `python manage.py available_tasks` to view all available tasks
236
+
237
+ _Requires `django_qstash.schedules` installed._
238
+ - `python manage.py task_schedules --list` see all schedules relate to the `DJANGO_QSTASH_DOMAIN`
239
+ - `python manage.py task_schedules --sync` sync schedules based on the `DJANGO_QSTASH_DOMAIN` to store in the Django Admin.
240
+
241
+ ## Development Usage
242
+
243
+ django-qstash requires a public domain to work (e.g. `https://djangoqstash.com`). There are many ways to do this, we recommend:
244
+
245
+ - [Cloudflare Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) with a domain name you control.
246
+ - [ngrok](https://ngrok.com/)
247
+
248
+ Once you have a domain name, you can configure the `DJANGO_QSTASH_DOMAIN` setting in your Django settings.
249
+
250
+
251
+ ## Django Settings Configuration
229
252
 
230
253
  In Django settings, you can configure the following:
231
254
 
232
- `DJANGO_QSTASH_DOMAIN`: Must be a valid and publicly accessible domain. For example `https://djangoqstash.com`
255
+ - `DJANGO_QSTASH_DOMAIN`: Must be a valid and publicly accessible domain. For example `https://djangoqstash.com`. Review [Development usage](#development-usage) for setting up a domain name during development.
256
+
257
+ - `DJANGO_QSTASH_WEBHOOK_PATH` (default:`/qstash/webhook/`): The path where QStash will send webhooks to your Django application.
233
258
 
234
- In development mode, we recommend using a tunnel like [Cloudflare Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) with a domain name you control. You can also consider [ngrok](https://ngrok.com/).
259
+ - `DJANGO_QSTASH_FORCE_HTTPS` (default:`True`): Whether to force HTTPS for the webhook.
235
260
 
236
- `DJANGO_QSTASH_WEBHOOK_PATH` (default:`/qstash/webhook/`): The path where QStash will send webhooks to your Django application.
261
+ - `DJANGO_QSTASH_RESULT_TTL` (default:`604800`): A number of seconds after which task result data can be safely deleted. Defaults to 604800 seconds (7 days or 7 * 24 * 60 * 60).
237
262
 
238
- `DJANGO_QSTASH_FORCE_HTTPS` (default:`True`): Whether to force HTTPS for the webhook.
239
263
 
240
- `DJANGO_QSTASH_RESULT_TTL` (default:`604800`): A number of seconds after which task result data can be safely deleted. Defaults to 604800 seconds (7 days or 7 * 24 * 60 * 60).
264
+ ## Schedule Tasks (Optional)
241
265
 
266
+ The `django_qstash.schedules` app schedules tasks using Upstash [QStash Schedules](https://upstash.com/docs/qstash/features/schedules) and the django-qstash `@shared_task` decorator.
242
267
 
243
- ## Storing Task Results (Optional)
268
+ ### Installation
269
+
270
+ Update your `INSTALLED_APPS` setting to include `django_qstash.schedules`.
271
+
272
+ ```python
273
+ INSTALLED_APPS = [
274
+ # ...
275
+ "django_qstash", # required
276
+ "django_qstash.schedules",
277
+ # ...
278
+ ]
279
+ ```
280
+
281
+ Run migrations:
282
+ ```bash
283
+ python manage.py migrate django_qstash_schedules
284
+ ```
285
+
286
+
287
+ ## Schedule a Task
288
+
289
+ Tasks must exist before you can schedule them. Review [Define a Task](#define-a-task) for more information.
290
+
291
+ Here's how you can schedule a task:
292
+ - Django Admin (`/admin/django_qstash_schedules/taskschedule/add/`)
293
+ - Django shell (`python manage.py shell`)
294
+
295
+
296
+
297
+
298
+ ```python
299
+ from django_qstash.schedules.models import TaskSchedule
300
+ from django_qstash.discovery.utils import discover_tasks
301
+
302
+ all_available_tasks = discover_tasks(paths_only=True)
303
+
304
+ desired_task = "django_qstash.results.clear_stale_results_task"
305
+ # or desired_task = "example_app.tasks.my_task"
306
+
307
+ task_to_use = desired_task
308
+ if desired_task not in available_task_locations:
309
+ task_to_use = available_task_locations[0]
310
+
311
+ print(f"Using task: {task_to_use}")
312
+
313
+ TaskSchedule.objects.create(
314
+ name="My Schedule",
315
+ cron="0 0 * * *",
316
+ task_name=task_to_use,
317
+ args=["arg1", "arg2"],
318
+ kwargs={"kwarg1": "value1", "kwarg2": "value2"},
319
+ )
320
+ ```
321
+ - `django_qstash.results.clear_stale_results_task` is a built-in task that `django_qstash.results` provides
322
+ - `args` and `kwargs` are the arguments to pass to the task
323
+ - `cron` is the cron schedule to run the task. Use [contrab.guru](https://crontab.guru/) for writing the cron format.
324
+
325
+
326
+
327
+ ## Store Task Results (Optional)
244
328
 
245
329
  In `django_qstash.results.models` we have the `TaskResult` model class that can be used to track async task results. These entries are created via webhooks.
246
330
 
@@ -249,6 +333,7 @@ To install it, just add `django_qstash.results` to your `INSTALLED_APPS` setting
249
333
  ```python
250
334
  INSTALLED_APPS = [
251
335
  # ...
336
+ "django_qstash",
252
337
  "django_qstash.results",
253
338
  # ...
254
339
  ]
@@ -256,14 +341,14 @@ INSTALLED_APPS = [
256
341
 
257
342
  Run migrations:
258
343
  ```bash
259
- python manage.py migrate
344
+ python manage.py migrate django_qstash_results
260
345
  ```
261
346
 
262
347
  ### Clear Stale Results
263
348
 
264
349
  We recommend purging the `TaskResult` model after a certain amount of time.
265
350
  ```bash
266
- python manage.py clear_stale_results
351
+ python manage.py clear_stale_results --since 604800
267
352
  ```
268
353
  Args:
269
354
  - `--since` is the number of seconds ago to clear results for. Defaults to 604800 seconds (7 days or the `DJANGO_QSTASH_RESULT_TTL` setting).
@@ -6,7 +6,7 @@ requires = [
6
6
 
7
7
  [project]
8
8
  name = "django-qstash"
9
- version = "0.0.9"
9
+ version = "0.0.10"
10
10
  description = "A drop-in replacement for Celery's shared_task with Upstash QStash."
11
11
  readme = "README.md"
12
12
  license = { file = "LICENSE" }
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.0.9"
3
+ __version__ = "0.0.10"
4
4
 
5
5
  from django_qstash.app import shared_task
6
6
 
@@ -16,10 +16,10 @@ class TaskChoiceField(forms.ChoiceField):
16
16
  kwargs.pop("max_length", None)
17
17
 
18
18
  # Get tasks before calling parent to set choices
19
- tasks = discover_tasks()
19
+ tasks = discover_tasks(locations_only=False)
20
20
 
21
21
  # Convert tasks to choices using (task_name, task_name) format
22
- task_choices = [(task_value, task_label) for task_value, task_label in tasks]
22
+ task_choices = [(task["location"], task["field_label"]) for task in tasks]
23
23
 
24
24
  kwargs["choices"] = task_choices
25
25
  kwargs["validators"] = [task_exists_validator] + kwargs.get("validators", [])
@@ -30,9 +30,9 @@ class TaskChoiceField(forms.ChoiceField):
30
30
  Returns the actual task dot notation path for the selected value
31
31
  """
32
32
  if self.data:
33
- tasks = discover_tasks()
33
+ tasks = discover_tasks(locations_only=False)
34
34
 
35
- for task_value, task_label in tasks:
36
- if task_label == self.data:
37
- return task_value
35
+ for task in tasks:
36
+ if task["field_label"] == self.data:
37
+ return task["location"]
38
38
  return None
@@ -19,7 +19,7 @@ DJANGO_QSTASH_DISCOVER_INCLUDE_SETTINGS_DIR = getattr(
19
19
 
20
20
 
21
21
  @lru_cache(maxsize=None)
22
- def discover_tasks() -> list[tuple[str, str]]:
22
+ def discover_tasks(locations_only: bool = False) -> list[str] | list[dict]:
23
23
  """
24
24
  Automatically discover tasks in Django apps and return them as a list of tuples.
25
25
  Each tuple contains (dot_notation_path, task_name).
@@ -72,13 +72,21 @@ def discover_tasks() -> list[tuple[str, str]]:
72
72
  label = value
73
73
  else:
74
74
  label = f"{attr.name} ({package}.tasks)"
75
- discovered_tasks.append((value, label))
75
+ discovered_tasks.append(
76
+ {
77
+ "name": attr.name,
78
+ "field_label": label,
79
+ "location": f"{package}.tasks.{attr_name}",
80
+ }
81
+ )
76
82
  except Exception as e:
77
83
  warnings.warn(
78
84
  f"Failed to import tasks from {package}: {str(e)}",
79
85
  RuntimeWarning,
80
86
  stacklevel=2,
81
87
  )
88
+ if locations_only:
89
+ return [x["location"] for x in discovered_tasks]
82
90
  return discovered_tasks
83
91
 
84
92
 
@@ -15,8 +15,8 @@ def task_exists_validator(task_name):
15
15
  Raises:
16
16
  ValidationError: If the task cannot be found
17
17
  """
18
- tasks = discover_tasks()
19
- available_tasks = [task[0] for task in tasks]
18
+ discover_tasks.cache_clear()
19
+ available_tasks = discover_tasks(locations_only=True)
20
20
 
21
21
  if task_name not in available_tasks:
22
22
  raise ValidationError(
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ from django.core.management.base import BaseCommand
4
+
5
+ from django_qstash.discovery.utils import discover_tasks
6
+
7
+
8
+ class Command(BaseCommand):
9
+ help = "View all available tasks"
10
+
11
+ def add_arguments(self, parser):
12
+ parser.add_argument(
13
+ "--locations",
14
+ action="store_true",
15
+ help="Only show task paths",
16
+ )
17
+
18
+ def handle(self, *args, **options):
19
+ locations_only = options["locations"] or False
20
+ self.stdout.write("Available tasks:")
21
+ discover_tasks.cache_clear()
22
+ if locations_only:
23
+ tasks = discover_tasks(locations_only=locations_only)
24
+ for task in tasks:
25
+ self.stdout.write(f"\t- {self.style.SQL_FIELD(task)}")
26
+ else:
27
+ tasks = discover_tasks(locations_only=False)
28
+ for task in tasks:
29
+ name = task["name"]
30
+ field_label = task["field_label"]
31
+ location = task["location"]
32
+ self.stdout.write(
33
+ f" Name: {self.style.SQL_FIELD(name)}\n"
34
+ f" Location: {self.style.SQL_FIELD(location)}\n"
35
+ f" Field Label: {self.style.SQL_FIELD(field_label)}"
36
+ )
37
+ self.stdout.write("")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-qstash
3
- Version: 0.0.9
3
+ Version: 0.0.10
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
@@ -68,8 +68,13 @@ This allows us to:
68
68
  - [`.apply_async()` With Time Delay](#apply_async-with-time-delay)
69
69
  - [JSON-ready Arguments](#json-ready-arguments)
70
70
  - [Example Task](#example-task)
71
- - [Configuration](#configuration)
72
- - [Storing Task Results (Optional)](#storing-task-results-optional)
71
+ - [Management Commands](#management-commands)
72
+ - [Development Usage](#development-usage)
73
+ - [Django Settings Configuration](#django-settings-configuration)
74
+ - [Schedule Tasks (Optional)](#schedule-tasks-optional)
75
+ - [Installation](#installation-1)
76
+ - [Schedule a Task](#schedule-a-task)
77
+ - [Store Task Results (Optional)](#store-task-results-optional)
73
78
  - [Clear Stale Results](#clear-stale-results)
74
79
  - [Definitions](#definitions)
75
80
  - [Motivation](#motivation)
@@ -89,12 +94,13 @@ INSTALLED_APPS = [
89
94
  ##...
90
95
  "django_qstash",
91
96
  "django_qstash.results",
97
+ "django_qstash.schedules",
92
98
  ##...
93
99
  ]
94
100
  ```
95
101
  - `django_qstash` Includes the `@shared_task` decorator and webhook view
96
102
  - `django_qstash.results` (Optional): Store task results in Django DB
97
-
103
+ - `django_qstash.schedules` (Optional): Use QStash Schedules to run your `django_qstash` tasks. Out of the box support for _django_qstash_ `@shared_task`. Schedule tasks using _cron_ (e.g. `0 0 * * *`) format which is required based on [QStash Schedules](https://upstash.com/docs/qstash/features/schedules). use [contrab.guru](https://crontab.guru/) for writing the cron format.
98
104
 
99
105
  ### Configure Webhook URL
100
106
 
@@ -157,7 +163,6 @@ def hello_world(name: str, age: int = None, activity: str = None):
157
163
  print(f"Hello {name}! I see you're {activity} at {age} years old.")
158
164
  ```
159
165
 
160
-
161
166
  ### Regular Task Call
162
167
  Nothing special here. Just call the function like any other to verify it works.
163
168
 
@@ -254,22 +259,101 @@ math_add_task.apply_async(
254
259
  The `.delay()` method does not support a countdown parameter because it simply passes the arguments (*args, **kwargs) to the `apply_async()` method.
255
260
 
256
261
 
257
- ## Configuration
262
+ ## Management Commands
263
+
264
+ - `python manage.py available_tasks` to view all available tasks
265
+
266
+ _Requires `django_qstash.schedules` installed._
267
+ - `python manage.py task_schedules --list` see all schedules relate to the `DJANGO_QSTASH_DOMAIN`
268
+ - `python manage.py task_schedules --sync` sync schedules based on the `DJANGO_QSTASH_DOMAIN` to store in the Django Admin.
269
+
270
+ ## Development Usage
271
+
272
+ django-qstash requires a public domain to work (e.g. `https://djangoqstash.com`). There are many ways to do this, we recommend:
273
+
274
+ - [Cloudflare Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) with a domain name you control.
275
+ - [ngrok](https://ngrok.com/)
276
+
277
+ Once you have a domain name, you can configure the `DJANGO_QSTASH_DOMAIN` setting in your Django settings.
278
+
279
+
280
+ ## Django Settings Configuration
258
281
 
259
282
  In Django settings, you can configure the following:
260
283
 
261
- `DJANGO_QSTASH_DOMAIN`: Must be a valid and publicly accessible domain. For example `https://djangoqstash.com`
284
+ - `DJANGO_QSTASH_DOMAIN`: Must be a valid and publicly accessible domain. For example `https://djangoqstash.com`. Review [Development usage](#development-usage) for setting up a domain name during development.
285
+
286
+ - `DJANGO_QSTASH_WEBHOOK_PATH` (default:`/qstash/webhook/`): The path where QStash will send webhooks to your Django application.
262
287
 
263
- In development mode, we recommend using a tunnel like [Cloudflare Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) with a domain name you control. You can also consider [ngrok](https://ngrok.com/).
288
+ - `DJANGO_QSTASH_FORCE_HTTPS` (default:`True`): Whether to force HTTPS for the webhook.
264
289
 
265
- `DJANGO_QSTASH_WEBHOOK_PATH` (default:`/qstash/webhook/`): The path where QStash will send webhooks to your Django application.
290
+ - `DJANGO_QSTASH_RESULT_TTL` (default:`604800`): A number of seconds after which task result data can be safely deleted. Defaults to 604800 seconds (7 days or 7 * 24 * 60 * 60).
266
291
 
267
- `DJANGO_QSTASH_FORCE_HTTPS` (default:`True`): Whether to force HTTPS for the webhook.
268
292
 
269
- `DJANGO_QSTASH_RESULT_TTL` (default:`604800`): A number of seconds after which task result data can be safely deleted. Defaults to 604800 seconds (7 days or 7 * 24 * 60 * 60).
293
+ ## Schedule Tasks (Optional)
270
294
 
295
+ The `django_qstash.schedules` app schedules tasks using Upstash [QStash Schedules](https://upstash.com/docs/qstash/features/schedules) and the django-qstash `@shared_task` decorator.
271
296
 
272
- ## Storing Task Results (Optional)
297
+ ### Installation
298
+
299
+ Update your `INSTALLED_APPS` setting to include `django_qstash.schedules`.
300
+
301
+ ```python
302
+ INSTALLED_APPS = [
303
+ # ...
304
+ "django_qstash", # required
305
+ "django_qstash.schedules",
306
+ # ...
307
+ ]
308
+ ```
309
+
310
+ Run migrations:
311
+ ```bash
312
+ python manage.py migrate django_qstash_schedules
313
+ ```
314
+
315
+
316
+ ## Schedule a Task
317
+
318
+ Tasks must exist before you can schedule them. Review [Define a Task](#define-a-task) for more information.
319
+
320
+ Here's how you can schedule a task:
321
+ - Django Admin (`/admin/django_qstash_schedules/taskschedule/add/`)
322
+ - Django shell (`python manage.py shell`)
323
+
324
+
325
+
326
+
327
+ ```python
328
+ from django_qstash.schedules.models import TaskSchedule
329
+ from django_qstash.discovery.utils import discover_tasks
330
+
331
+ all_available_tasks = discover_tasks(paths_only=True)
332
+
333
+ desired_task = "django_qstash.results.clear_stale_results_task"
334
+ # or desired_task = "example_app.tasks.my_task"
335
+
336
+ task_to_use = desired_task
337
+ if desired_task not in available_task_locations:
338
+ task_to_use = available_task_locations[0]
339
+
340
+ print(f"Using task: {task_to_use}")
341
+
342
+ TaskSchedule.objects.create(
343
+ name="My Schedule",
344
+ cron="0 0 * * *",
345
+ task_name=task_to_use,
346
+ args=["arg1", "arg2"],
347
+ kwargs={"kwarg1": "value1", "kwarg2": "value2"},
348
+ )
349
+ ```
350
+ - `django_qstash.results.clear_stale_results_task` is a built-in task that `django_qstash.results` provides
351
+ - `args` and `kwargs` are the arguments to pass to the task
352
+ - `cron` is the cron schedule to run the task. Use [contrab.guru](https://crontab.guru/) for writing the cron format.
353
+
354
+
355
+
356
+ ## Store Task Results (Optional)
273
357
 
274
358
  In `django_qstash.results.models` we have the `TaskResult` model class that can be used to track async task results. These entries are created via webhooks.
275
359
 
@@ -278,6 +362,7 @@ To install it, just add `django_qstash.results` to your `INSTALLED_APPS` setting
278
362
  ```python
279
363
  INSTALLED_APPS = [
280
364
  # ...
365
+ "django_qstash",
281
366
  "django_qstash.results",
282
367
  # ...
283
368
  ]
@@ -285,14 +370,14 @@ INSTALLED_APPS = [
285
370
 
286
371
  Run migrations:
287
372
  ```bash
288
- python manage.py migrate
373
+ python manage.py migrate django_qstash_results
289
374
  ```
290
375
 
291
376
  ### Clear Stale Results
292
377
 
293
378
  We recommend purging the `TaskResult` model after a certain amount of time.
294
379
  ```bash
295
- python manage.py clear_stale_results
380
+ python manage.py clear_stale_results --since 604800
296
381
  ```
297
382
  Args:
298
383
  - `--since` is the number of seconds ago to clear results for. Defaults to 604800 seconds (7 days or the `DJANGO_QSTASH_RESULT_TTL` setting).
@@ -23,6 +23,7 @@ src/django_qstash/discovery/utils.py
23
23
  src/django_qstash/discovery/validators.py
24
24
  src/django_qstash/management/__init__.py
25
25
  src/django_qstash/management/commands/__init__.py
26
+ src/django_qstash/management/commands/available_tasks.py
26
27
  src/django_qstash/management/commands/clear_stale_results.py
27
28
  src/django_qstash/management/commands/task_schedules.py
28
29
  src/django_qstash/results/__init__.py
File without changes