django-nativemojo 0.1.15__py3-none-any.whl → 0.1.16__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.
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.16.dist-info}/METADATA +3 -1
- django_nativemojo-0.1.16.dist-info/RECORD +302 -0
- mojo/__init__.py +1 -1
- mojo/apps/account/management/commands/serializer_admin.py +121 -1
- mojo/apps/account/migrations/0006_add_device_tracking_models.py +72 -0
- mojo/apps/account/migrations/0007_delete_userdevicelocation.py +16 -0
- mojo/apps/account/migrations/0008_userdevicelocation.py +33 -0
- mojo/apps/account/migrations/0009_geolocatedip_subnet.py +18 -0
- mojo/apps/account/migrations/0010_group_avatar.py +20 -0
- mojo/apps/account/migrations/0011_user_org_registereddevice_pushconfig_and_more.py +118 -0
- mojo/apps/account/migrations/0012_remove_pushconfig_apns_key_file_and_more.py +21 -0
- mojo/apps/account/migrations/0013_pushconfig_test_mode_alter_pushconfig_apns_enabled_and_more.py +28 -0
- mojo/apps/account/migrations/0014_notificationdelivery_data_payload_and_more.py +48 -0
- mojo/apps/account/models/__init__.py +2 -0
- mojo/apps/account/models/device.py +281 -0
- mojo/apps/account/models/group.py +294 -8
- mojo/apps/account/models/member.py +14 -1
- mojo/apps/account/models/push/__init__.py +4 -0
- mojo/apps/account/models/push/config.py +112 -0
- mojo/apps/account/models/push/delivery.py +93 -0
- mojo/apps/account/models/push/device.py +66 -0
- mojo/apps/account/models/push/template.py +99 -0
- mojo/apps/account/models/user.py +190 -17
- mojo/apps/account/rest/__init__.py +2 -0
- mojo/apps/account/rest/device.py +39 -0
- mojo/apps/account/rest/group.py +8 -0
- mojo/apps/account/rest/push.py +187 -0
- mojo/apps/account/rest/user.py +95 -5
- mojo/apps/account/services/__init__.py +1 -0
- mojo/apps/account/services/push.py +363 -0
- mojo/apps/aws/migrations/0001_initial.py +206 -0
- mojo/apps/aws/migrations/0002_emaildomain_can_recv_emaildomain_can_send_and_more.py +28 -0
- mojo/apps/aws/migrations/0003_mailbox_is_domain_default_mailbox_is_system_default_and_more.py +31 -0
- mojo/apps/aws/migrations/0004_s3bucket.py +39 -0
- mojo/apps/aws/migrations/0005_alter_emaildomain_region_delete_s3bucket.py +21 -0
- mojo/apps/aws/models/__init__.py +19 -0
- mojo/apps/aws/models/email_attachment.py +99 -0
- mojo/apps/aws/models/email_domain.py +218 -0
- mojo/apps/aws/models/email_template.py +132 -0
- mojo/apps/aws/models/incoming_email.py +197 -0
- mojo/apps/aws/models/mailbox.py +288 -0
- mojo/apps/aws/models/sent_message.py +175 -0
- mojo/apps/aws/rest/__init__.py +6 -0
- mojo/apps/aws/rest/email.py +33 -0
- mojo/apps/aws/rest/email_ops.py +183 -0
- mojo/apps/aws/rest/messages.py +32 -0
- mojo/apps/aws/rest/send.py +101 -0
- mojo/apps/aws/rest/sns.py +403 -0
- mojo/apps/aws/rest/templates.py +19 -0
- mojo/apps/aws/services/__init__.py +32 -0
- mojo/apps/aws/services/email.py +390 -0
- mojo/apps/aws/services/email_ops.py +548 -0
- mojo/apps/docit/__init__.py +6 -0
- mojo/apps/docit/markdown_plugins/syntax_highlight.py +25 -0
- mojo/apps/docit/markdown_plugins/toc.py +12 -0
- mojo/apps/docit/migrations/0001_initial.py +113 -0
- mojo/apps/docit/migrations/0002_alter_book_modified_by_alter_page_modified_by.py +26 -0
- mojo/apps/docit/migrations/0003_alter_book_group.py +20 -0
- mojo/apps/docit/models/__init__.py +17 -0
- mojo/apps/docit/models/asset.py +231 -0
- mojo/apps/docit/models/book.py +227 -0
- mojo/apps/docit/models/page.py +319 -0
- mojo/apps/docit/models/page_revision.py +203 -0
- mojo/apps/docit/rest/__init__.py +10 -0
- mojo/apps/docit/rest/asset.py +17 -0
- mojo/apps/docit/rest/book.py +22 -0
- mojo/apps/docit/rest/page.py +22 -0
- mojo/apps/docit/rest/page_revision.py +17 -0
- mojo/apps/docit/services/__init__.py +11 -0
- mojo/apps/docit/services/docit.py +315 -0
- mojo/apps/docit/services/markdown.py +44 -0
- mojo/apps/fileman/backends/s3.py +209 -0
- mojo/apps/fileman/models/file.py +45 -9
- mojo/apps/fileman/models/manager.py +269 -3
- mojo/apps/incident/migrations/0007_event_uid.py +18 -0
- mojo/apps/incident/migrations/0008_ticket_ticketnote.py +55 -0
- mojo/apps/incident/migrations/0009_incident_status.py +18 -0
- mojo/apps/incident/migrations/0010_event_country_code.py +18 -0
- mojo/apps/incident/migrations/0011_incident_country_code.py +18 -0
- mojo/apps/incident/migrations/0012_alter_incident_status.py +18 -0
- mojo/apps/incident/models/__init__.py +1 -0
- mojo/apps/incident/models/event.py +35 -0
- mojo/apps/incident/models/incident.py +2 -0
- mojo/apps/incident/models/ticket.py +62 -0
- mojo/apps/incident/reporter.py +21 -3
- mojo/apps/incident/rest/__init__.py +1 -0
- mojo/apps/incident/rest/ticket.py +43 -0
- mojo/apps/jobs/__init__.py +489 -0
- mojo/apps/jobs/adapters.py +24 -0
- mojo/apps/jobs/cli.py +616 -0
- mojo/apps/jobs/daemon.py +370 -0
- mojo/apps/jobs/examples/sample_jobs.py +376 -0
- mojo/apps/jobs/examples/webhook_examples.py +203 -0
- mojo/apps/jobs/handlers/__init__.py +5 -0
- mojo/apps/jobs/handlers/webhook.py +317 -0
- mojo/apps/jobs/job_engine.py +734 -0
- mojo/apps/jobs/keys.py +203 -0
- mojo/apps/jobs/local_queue.py +363 -0
- mojo/apps/jobs/management/__init__.py +3 -0
- mojo/apps/jobs/management/commands/__init__.py +3 -0
- mojo/apps/jobs/manager.py +1327 -0
- mojo/apps/jobs/migrations/0001_initial.py +97 -0
- mojo/apps/jobs/migrations/0002_alter_job_max_retries_joblog.py +39 -0
- mojo/apps/jobs/models/__init__.py +6 -0
- mojo/apps/jobs/models/job.py +441 -0
- mojo/apps/jobs/rest/__init__.py +2 -0
- mojo/apps/jobs/rest/control.py +466 -0
- mojo/apps/jobs/rest/jobs.py +421 -0
- mojo/apps/jobs/scheduler.py +571 -0
- mojo/apps/jobs/services/__init__.py +6 -0
- mojo/apps/jobs/services/job_actions.py +465 -0
- mojo/apps/jobs/settings.py +209 -0
- mojo/apps/logit/models/log.py +3 -0
- mojo/apps/metrics/__init__.py +8 -1
- mojo/apps/metrics/redis_metrics.py +198 -0
- mojo/apps/metrics/rest/__init__.py +3 -0
- mojo/apps/metrics/rest/categories.py +266 -0
- mojo/apps/metrics/rest/helpers.py +48 -0
- mojo/apps/metrics/rest/permissions.py +99 -0
- mojo/apps/metrics/rest/values.py +277 -0
- mojo/apps/metrics/utils.py +17 -0
- mojo/decorators/http.py +40 -1
- mojo/helpers/aws/__init__.py +11 -7
- mojo/helpers/aws/inbound_email.py +309 -0
- mojo/helpers/aws/kms.py +413 -0
- mojo/helpers/aws/ses_domain.py +959 -0
- mojo/helpers/crypto/__init__.py +1 -1
- mojo/helpers/crypto/utils.py +15 -0
- mojo/helpers/location/__init__.py +2 -0
- mojo/helpers/location/countries.py +262 -0
- mojo/helpers/location/geolocation.py +196 -0
- mojo/helpers/logit.py +37 -0
- mojo/helpers/redis/__init__.py +2 -0
- mojo/helpers/redis/adapter.py +606 -0
- mojo/helpers/redis/client.py +48 -0
- mojo/helpers/redis/pool.py +225 -0
- mojo/helpers/request.py +8 -0
- mojo/helpers/response.py +8 -0
- mojo/middleware/auth.py +1 -1
- mojo/middleware/cors.py +40 -0
- mojo/middleware/logging.py +131 -12
- mojo/middleware/mojo.py +5 -0
- mojo/models/rest.py +271 -57
- mojo/models/secrets.py +86 -0
- mojo/serializers/__init__.py +16 -10
- mojo/serializers/core/__init__.py +90 -0
- mojo/serializers/core/cache/__init__.py +121 -0
- mojo/serializers/core/cache/backends.py +518 -0
- mojo/serializers/core/cache/base.py +102 -0
- mojo/serializers/core/cache/disabled.py +181 -0
- mojo/serializers/core/cache/memory.py +287 -0
- mojo/serializers/core/cache/redis.py +533 -0
- mojo/serializers/core/cache/utils.py +454 -0
- mojo/serializers/{manager.py → core/manager.py} +53 -4
- mojo/serializers/core/serializer.py +475 -0
- mojo/serializers/{advanced/formats → formats}/csv.py +116 -139
- mojo/serializers/suggested_improvements.md +388 -0
- testit/client.py +1 -1
- testit/helpers.py +14 -0
- testit/runner.py +23 -6
- django_nativemojo-0.1.15.dist-info/RECORD +0 -234
- mojo/apps/notify/README.md +0 -91
- mojo/apps/notify/README_NOTIFICATIONS.md +0 -566
- mojo/apps/notify/admin.py +0 -52
- mojo/apps/notify/handlers/example_handlers.py +0 -516
- mojo/apps/notify/handlers/ses/__init__.py +0 -25
- mojo/apps/notify/handlers/ses/complaint.py +0 -25
- mojo/apps/notify/handlers/ses/message.py +0 -86
- mojo/apps/notify/management/commands/__init__.py +0 -1
- mojo/apps/notify/management/commands/process_notifications.py +0 -370
- mojo/apps/notify/mod +0 -0
- mojo/apps/notify/models/__init__.py +0 -12
- mojo/apps/notify/models/account.py +0 -128
- mojo/apps/notify/models/attachment.py +0 -24
- mojo/apps/notify/models/bounce.py +0 -68
- mojo/apps/notify/models/complaint.py +0 -40
- mojo/apps/notify/models/inbox.py +0 -113
- mojo/apps/notify/models/inbox_message.py +0 -173
- mojo/apps/notify/models/outbox.py +0 -129
- mojo/apps/notify/models/outbox_message.py +0 -288
- mojo/apps/notify/models/template.py +0 -30
- mojo/apps/notify/providers/aws.py +0 -73
- mojo/apps/notify/rest/ses.py +0 -0
- mojo/apps/notify/utils/__init__.py +0 -2
- mojo/apps/notify/utils/notifications.py +0 -404
- mojo/apps/notify/utils/parsing.py +0 -202
- mojo/apps/notify/utils/render.py +0 -144
- mojo/apps/tasks/README.md +0 -118
- mojo/apps/tasks/__init__.py +0 -44
- mojo/apps/tasks/manager.py +0 -644
- mojo/apps/tasks/rest/__init__.py +0 -2
- mojo/apps/tasks/rest/hooks.py +0 -0
- mojo/apps/tasks/rest/tasks.py +0 -76
- mojo/apps/tasks/runner.py +0 -439
- mojo/apps/tasks/task.py +0 -99
- mojo/apps/tasks/tq_handlers.py +0 -132
- mojo/helpers/crypto/__pycache__/hash.cpython-310.pyc +0 -0
- mojo/helpers/crypto/__pycache__/sign.cpython-310.pyc +0 -0
- mojo/helpers/crypto/__pycache__/utils.cpython-310.pyc +0 -0
- mojo/helpers/redis.py +0 -10
- mojo/models/meta.py +0 -262
- mojo/serializers/advanced/README.md +0 -363
- mojo/serializers/advanced/__init__.py +0 -247
- mojo/serializers/advanced/formats/__init__.py +0 -28
- mojo/serializers/advanced/formats/excel.py +0 -516
- mojo/serializers/advanced/formats/json.py +0 -239
- mojo/serializers/advanced/formats/response.py +0 -485
- mojo/serializers/advanced/serializer.py +0 -568
- mojo/serializers/optimized.py +0 -618
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.16.dist-info}/LICENSE +0 -0
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.16.dist-info}/NOTICE +0 -0
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.16.dist-info}/WHEEL +0 -0
- /mojo/apps/{notify → aws/migrations}/__init__.py +0 -0
- /mojo/apps/{notify/handlers → docit/markdown_plugins}/__init__.py +0 -0
- /mojo/apps/{notify/management → docit/migrations}/__init__.py +0 -0
- /mojo/apps/{notify/providers → jobs/examples}/__init__.py +0 -0
- /mojo/apps/{notify/rest → jobs/migrations}/__init__.py +0 -0
- /mojo/{serializers → rest}/openapi.py +0 -0
- /mojo/serializers/{settings_example.py → examples/settings.py} +0 -0
- /mojo/{apps/notify/handlers/ses/bounce.py → serializers/formats/__init__.py} +0 -0
- /mojo/serializers/{advanced/formats → formats}/localizers.py +0 -0
mojo/apps/tasks/manager.py
DELETED
@@ -1,644 +0,0 @@
|
|
1
|
-
from posix import lockf
|
2
|
-
from venv import create
|
3
|
-
from mojo.helpers import redis
|
4
|
-
from objict import objict
|
5
|
-
import uuid
|
6
|
-
import time
|
7
|
-
|
8
|
-
|
9
|
-
class TaskManager:
|
10
|
-
def __init__(self, channels, prefix="mojo:tasks"):
|
11
|
-
"""
|
12
|
-
Initialize the TaskManager with Redis connection, channels, and a key prefix.
|
13
|
-
|
14
|
-
:param channels: List of channels for task management.
|
15
|
-
:param prefix: Prefix for Redis keys. Default is "taskit".
|
16
|
-
"""
|
17
|
-
self.redis = redis.get_connection()
|
18
|
-
self.channels = channels
|
19
|
-
self.prefix = prefix
|
20
|
-
|
21
|
-
def take_out_the_dead(self, local=False):
|
22
|
-
# Get channels from Redis instead of using self.channels
|
23
|
-
channels = self.channels if local else self.get_all_channels()
|
24
|
-
for channel in channels:
|
25
|
-
# this will remove all expired tasks by default
|
26
|
-
self.get_pending(channel)
|
27
|
-
self.get_running(channel)
|
28
|
-
|
29
|
-
def get_completed_key(self, channel):
|
30
|
-
"""
|
31
|
-
Get the Redis key for completed tasks in a channel.
|
32
|
-
|
33
|
-
:param channel: Channel name.
|
34
|
-
:return: Redis key for completed tasks.
|
35
|
-
"""
|
36
|
-
return f"{self.prefix}:d:{channel}"
|
37
|
-
|
38
|
-
def get_pending_key(self, channel):
|
39
|
-
"""
|
40
|
-
Get the Redis key for pending tasks in a channel.
|
41
|
-
|
42
|
-
:param channel: Channel name.
|
43
|
-
:return: Redis key for pending tasks.
|
44
|
-
"""
|
45
|
-
return f"{self.prefix}:p:{channel}"
|
46
|
-
|
47
|
-
def get_global_pending_key(self):
|
48
|
-
"""
|
49
|
-
Get the Redis key for pending tasks in a channel.
|
50
|
-
|
51
|
-
:param channel: Channel name.
|
52
|
-
:return: Redis key for pending tasks.
|
53
|
-
"""
|
54
|
-
return f"{self.prefix}:pending"
|
55
|
-
|
56
|
-
def get_channels_key(self):
|
57
|
-
"""
|
58
|
-
Get the Redis key for tracking all channels.
|
59
|
-
|
60
|
-
:return: Redis key for channels set.
|
61
|
-
"""
|
62
|
-
return f"{self.prefix}:channels"
|
63
|
-
|
64
|
-
def get_error_key(self, channel):
|
65
|
-
"""
|
66
|
-
Get the Redis key for tasks with errors in a channel.
|
67
|
-
|
68
|
-
:param channel: Channel name.
|
69
|
-
:return: Redis key for tasks with errors.
|
70
|
-
"""
|
71
|
-
return f"{self.prefix}:e:{channel}"
|
72
|
-
|
73
|
-
def get_running_key(self, channel):
|
74
|
-
"""
|
75
|
-
Get the Redis key for running tasks in a channel.
|
76
|
-
|
77
|
-
:param channel: Channel name.
|
78
|
-
:return: Redis key for running tasks.
|
79
|
-
"""
|
80
|
-
return f"{self.prefix}:r:{channel}"
|
81
|
-
|
82
|
-
def get_task_key(self, task_id):
|
83
|
-
"""
|
84
|
-
Get the Redis key for a specific task.
|
85
|
-
|
86
|
-
:param task_id: Task ID.
|
87
|
-
:return: Redis key for the task.
|
88
|
-
"""
|
89
|
-
return f"{self.prefix}:t:{task_id}"
|
90
|
-
|
91
|
-
def get_channel_key(self, channel):
|
92
|
-
"""
|
93
|
-
Get the Redis key for a channel.
|
94
|
-
|
95
|
-
:param channel: Channel name.
|
96
|
-
:return: Redis key for the channel.
|
97
|
-
"""
|
98
|
-
return f"{self.prefix}:c:{channel}"
|
99
|
-
|
100
|
-
def get_runners_key(self):
|
101
|
-
return f"{self.prefix}:runners"
|
102
|
-
|
103
|
-
def add_channel(self, channel):
|
104
|
-
"""
|
105
|
-
Add a channel to the global channels set.
|
106
|
-
|
107
|
-
:param channel: Channel name.
|
108
|
-
"""
|
109
|
-
self.redis.sadd(self.get_channels_key(), channel)
|
110
|
-
|
111
|
-
def remove_channel(self, channel):
|
112
|
-
"""
|
113
|
-
Remove a channel from the global channels set.
|
114
|
-
|
115
|
-
:param channel: Channel name.
|
116
|
-
"""
|
117
|
-
self.redis.srem(self.get_channels_key(), channel)
|
118
|
-
|
119
|
-
def remove_all_channels(self):
|
120
|
-
"""
|
121
|
-
Remove all channels from the global channels set.
|
122
|
-
"""
|
123
|
-
self.redis.delete(self.get_channels_key())
|
124
|
-
|
125
|
-
def get_all_channels(self):
|
126
|
-
"""
|
127
|
-
Get all channels from the global channels set.
|
128
|
-
|
129
|
-
:return: List of channel names.
|
130
|
-
"""
|
131
|
-
channels = self.redis.smembers(self.get_channels_key())
|
132
|
-
return [channel.decode('utf-8') for channel in channels]
|
133
|
-
|
134
|
-
def get_task(self, task_id):
|
135
|
-
"""
|
136
|
-
Retrieve a task from Redis using its task ID.
|
137
|
-
|
138
|
-
:param task_id: Task ID.
|
139
|
-
:return: Task data as an objict, or None if not found.
|
140
|
-
"""
|
141
|
-
task_data_raw = self.redis.get(self.get_task_key(task_id))
|
142
|
-
if not task_data_raw:
|
143
|
-
return None
|
144
|
-
return objict.from_json(task_data_raw, ignore_errors=True)
|
145
|
-
|
146
|
-
def save_task(self, task_data, expires=1800):
|
147
|
-
"""
|
148
|
-
Save a task to Redis with an expiration time.
|
149
|
-
|
150
|
-
:param task_data: Task data as an objict.
|
151
|
-
:param expires: Expiration time in seconds. Default is 1800.
|
152
|
-
"""
|
153
|
-
self.redis.set(self.get_task_key(task_data.id), task_data.to_json(as_string=True), ex=expires)
|
154
|
-
|
155
|
-
def get_key_expiration(self, task_id):
|
156
|
-
"""
|
157
|
-
Get the expiration time of a task in Redis.
|
158
|
-
|
159
|
-
:param task_id: Task ID.
|
160
|
-
:return: Time to live for the task key in seconds, or None if the key does not exist.
|
161
|
-
"""
|
162
|
-
ttl = self.redis.ttl(self.get_task_key(task_id))
|
163
|
-
return ttl if ttl != -2 else None
|
164
|
-
|
165
|
-
def add_to_pending(self, task_id, channel="default"):
|
166
|
-
"""
|
167
|
-
Add a task ID to the pending set in Redis for a channel.
|
168
|
-
|
169
|
-
:param task_id: Task ID.
|
170
|
-
:param channel: Channel name. Default is "default".
|
171
|
-
:return: True if operation is successful.
|
172
|
-
"""
|
173
|
-
# Add channel to global channels set
|
174
|
-
self.add_channel(channel)
|
175
|
-
self.redis.sadd(self.get_pending_key(channel), task_id)
|
176
|
-
return True
|
177
|
-
|
178
|
-
def add_to_running(self, task_id, channel="default"):
|
179
|
-
"""
|
180
|
-
Add a task ID to the running set in Redis for a channel.
|
181
|
-
|
182
|
-
:param task_id: Task ID.
|
183
|
-
:param channel: Channel name. Default is "default".
|
184
|
-
:return: True if operation is successful.
|
185
|
-
"""
|
186
|
-
self.redis.sadd(self.get_running_key(channel), task_id)
|
187
|
-
return True
|
188
|
-
|
189
|
-
def add_to_errors(self, task_data, error_message):
|
190
|
-
"""
|
191
|
-
Add a task to the error set in Redis with an error message.
|
192
|
-
|
193
|
-
:param task_data: Task data as an objict.
|
194
|
-
:param error_message: Error message string.
|
195
|
-
:return: True if operation is successful.
|
196
|
-
"""
|
197
|
-
task_data.status = "error"
|
198
|
-
task_data.error = error_message
|
199
|
-
self.save_task(task_data, expires=86400)
|
200
|
-
self.redis.sadd(self.get_error_key(task_data.channel), task_data.id)
|
201
|
-
return True
|
202
|
-
|
203
|
-
def add_to_completed(self, task_data):
|
204
|
-
"""
|
205
|
-
Add a task to the completed set in Redis.
|
206
|
-
|
207
|
-
:param task_data: Task data as an objict.
|
208
|
-
:return: True if operation is successful.
|
209
|
-
"""
|
210
|
-
task_data.status = "completed"
|
211
|
-
# save completed tasks for 24 hours
|
212
|
-
self.save_task(task_data, expires=86400)
|
213
|
-
self.redis.sadd(self.get_completed_key(task_data.channel), task_data.id)
|
214
|
-
return True
|
215
|
-
|
216
|
-
def remove_from_running(self, task_id, channel="default"):
|
217
|
-
"""
|
218
|
-
Remove a task ID from the running set in Redis for a channel.
|
219
|
-
|
220
|
-
:param task_id: Task ID.
|
221
|
-
:param channel: Channel name. Default is "default".
|
222
|
-
:return: True if operation is successful.
|
223
|
-
"""
|
224
|
-
self.redis.srem(self.get_running_key(channel), task_id)
|
225
|
-
return True
|
226
|
-
|
227
|
-
def remove_from_pending(self, task_id, channel="default"):
|
228
|
-
"""
|
229
|
-
Remove a task ID from the pending set in Redis for a channel.
|
230
|
-
|
231
|
-
:param task_id: Task ID.
|
232
|
-
:param channel: Channel name. Default is "default".
|
233
|
-
:return: True if operation is successful.
|
234
|
-
"""
|
235
|
-
self.redis.srem(self.get_pending_key(channel), task_id)
|
236
|
-
return True
|
237
|
-
|
238
|
-
def remove_from_completed(self, task_id, channel="default"):
|
239
|
-
"""
|
240
|
-
Remove a task ID from the completed set in Redis for a channel.
|
241
|
-
|
242
|
-
:param task_id: Task ID.
|
243
|
-
:param channel: Channel name. Default is "default".
|
244
|
-
:return: True if operation is successful.
|
245
|
-
"""
|
246
|
-
self.redis.srem(self.get_completed_key(channel), task_id)
|
247
|
-
return True
|
248
|
-
|
249
|
-
def remove_from_errors(self, task_id, channel="default"):
|
250
|
-
"""
|
251
|
-
Remove a task ID from the error set in Redis for a channel.
|
252
|
-
|
253
|
-
:param task_id: Task ID.
|
254
|
-
:param channel: Channel name. Default is "default".
|
255
|
-
:return: True if operation is successful.
|
256
|
-
"""
|
257
|
-
self.redis.srem(self.get_error_key(channel), task_id)
|
258
|
-
return True
|
259
|
-
|
260
|
-
def remove_task(self, task_id):
|
261
|
-
"""
|
262
|
-
Remove a task from all sets and delete it from Redis.
|
263
|
-
|
264
|
-
:param task_id: Task ID.
|
265
|
-
:return: True if task was found and removed, otherwise False.
|
266
|
-
"""
|
267
|
-
task_data = self.get_task(task_id)
|
268
|
-
if task_data:
|
269
|
-
self.remove_from_running(task_data.id, task_data.channel)
|
270
|
-
self.remove_from_pending(task_data.id, task_data.channel)
|
271
|
-
self.redis.delete(self.get_task_key(task_id))
|
272
|
-
return True
|
273
|
-
return False
|
274
|
-
|
275
|
-
def cancel_task(self, task_id):
|
276
|
-
"""
|
277
|
-
Cancel a task by removing it from running and pending sets and deleting it.
|
278
|
-
|
279
|
-
:param task_id: Task ID.
|
280
|
-
"""
|
281
|
-
task_data_raw = self.redis.get(self.get_task_key(task_id))
|
282
|
-
task_data = objict.from_json(task_data_raw, ignore_errors=True)
|
283
|
-
if task_data:
|
284
|
-
task_data.status = "cancelled"
|
285
|
-
self.remove_from_pending(task_data.id, task_data.channel)
|
286
|
-
self.save_task(task_data)
|
287
|
-
return True
|
288
|
-
return False
|
289
|
-
|
290
|
-
def get_running_ids(self, channel="default"):
|
291
|
-
"""
|
292
|
-
Get all running task IDs from Redis for a channel.
|
293
|
-
|
294
|
-
:param channel: Channel name. Default is "default".
|
295
|
-
:return: List of running task IDs.
|
296
|
-
"""
|
297
|
-
return [task_id.decode('utf-8') for task_id in self.redis.smembers(self.get_running_key(channel))]
|
298
|
-
|
299
|
-
def get_pending_ids(self, channel="default"):
|
300
|
-
"""
|
301
|
-
Get all pending task IDs from Redis for a channel.
|
302
|
-
|
303
|
-
:param channel: Channel name. Default is "default".
|
304
|
-
:return: List of pending task IDs.
|
305
|
-
"""
|
306
|
-
return [task_id.decode('utf-8') for task_id in self.redis.smembers(self.get_pending_key(channel))]
|
307
|
-
|
308
|
-
def get_completed_ids(self, channel="default"):
|
309
|
-
"""
|
310
|
-
Get all pending task IDs from Redis for a channel.
|
311
|
-
|
312
|
-
:param channel: Channel name. Default is "default".
|
313
|
-
:return: List of pending task IDs.
|
314
|
-
"""
|
315
|
-
return [task_id.decode('utf-8') for task_id in self.redis.smembers(self.get_completed_key(channel))]
|
316
|
-
|
317
|
-
def get_error_ids(self, channel="default"):
|
318
|
-
"""
|
319
|
-
Get all error task IDs from Redis for a channel.
|
320
|
-
|
321
|
-
:param channel: Channel name. Default is "default".
|
322
|
-
:return: List of error task IDs.
|
323
|
-
"""
|
324
|
-
return [task_id.decode('utf-8') for task_id in self.redis.smembers(self.get_error_key(channel))]
|
325
|
-
|
326
|
-
def get_pending(self, channel="default"):
|
327
|
-
"""
|
328
|
-
Get all pending tasks as objicts for a channel.
|
329
|
-
|
330
|
-
:param channel: Channel name. Default is "default".
|
331
|
-
:return: List of pending task objicts.
|
332
|
-
"""
|
333
|
-
pending_tasks = []
|
334
|
-
for task_id in self.get_pending_ids(channel):
|
335
|
-
task = self.get_task(task_id)
|
336
|
-
if task:
|
337
|
-
pending_tasks.append(task)
|
338
|
-
else:
|
339
|
-
self.remove_from_pending(task_id, channel)
|
340
|
-
return pending_tasks
|
341
|
-
|
342
|
-
def get_running(self, channel="default"):
|
343
|
-
"""
|
344
|
-
Get all running tasks as objicts for a channel.
|
345
|
-
|
346
|
-
:param channel: Channel name. Default is "default".
|
347
|
-
:return: List of running task objicts.
|
348
|
-
"""
|
349
|
-
running_tasks = []
|
350
|
-
for task_id in self.get_running_ids(channel):
|
351
|
-
task = self.get_task(task_id)
|
352
|
-
if task:
|
353
|
-
running_tasks.append(task)
|
354
|
-
else:
|
355
|
-
self.remove_from_running(task_id, channel)
|
356
|
-
return running_tasks
|
357
|
-
|
358
|
-
def get_completed(self, channel="default"):
|
359
|
-
"""
|
360
|
-
Get all completed tasks as objicts for a channel.
|
361
|
-
|
362
|
-
:param channel: Channel name. Default is "default".
|
363
|
-
:return: List of completed task objicts.
|
364
|
-
"""
|
365
|
-
completed_tasks = []
|
366
|
-
for task_id in self.get_completed_ids(channel):
|
367
|
-
task = self.get_task(task_id)
|
368
|
-
if task:
|
369
|
-
completed_tasks.append(task)
|
370
|
-
else:
|
371
|
-
self.remove_from_completed(task_id, channel)
|
372
|
-
return completed_tasks
|
373
|
-
|
374
|
-
def get_errors(self, channel="default"):
|
375
|
-
"""
|
376
|
-
Get all error tasks as objicts for a channel.
|
377
|
-
|
378
|
-
:param channel: Channel name. Default is "default".
|
379
|
-
:return: List of error task objicts.
|
380
|
-
"""
|
381
|
-
error_tasks = []
|
382
|
-
for task_id in self.get_error_ids(channel):
|
383
|
-
task = self.get_task(task_id)
|
384
|
-
if task:
|
385
|
-
error_tasks.append(task)
|
386
|
-
else:
|
387
|
-
self.remove_from_errors(task_id, channel)
|
388
|
-
return error_tasks
|
389
|
-
|
390
|
-
def publish(self, function, data, channel="default", expires=1800):
|
391
|
-
"""
|
392
|
-
Publish a new task to a channel, save it, and add to pending tasks.
|
393
|
-
|
394
|
-
:param function: Function associated with the task.
|
395
|
-
:param data: Data to be processed by the task.
|
396
|
-
:param channel: Channel name. Default is "default".
|
397
|
-
:param expires: Expiration time in seconds. Default is 1800.
|
398
|
-
:return: Task ID of the published task.
|
399
|
-
"""
|
400
|
-
from mojo.apps import metrics
|
401
|
-
|
402
|
-
task_data = objict(channel=channel, function=function, data=objict.from_dict(data))
|
403
|
-
task_data.id = str(uuid.uuid4()).replace('-', '')
|
404
|
-
task_data.created = time.time()
|
405
|
-
task_data.expires = time.time() + expires
|
406
|
-
task_data.status = "pending"
|
407
|
-
self.add_to_pending(task_data.id, channel)
|
408
|
-
self.save_task(task_data, expires)
|
409
|
-
self.redis.publish(self.get_channel_key(channel), task_data.id)
|
410
|
-
metrics.record("tasks_pub", category="tasks")
|
411
|
-
metrics.record(f"tasks_pub_{channel}", category=f"tasks_{channel}")
|
412
|
-
return task_data.id
|
413
|
-
|
414
|
-
def get_all_pending_ids(self, local=False):
|
415
|
-
"""
|
416
|
-
Get all pending task IDs across all channels.
|
417
|
-
|
418
|
-
:return: List of all pending task IDs.
|
419
|
-
"""
|
420
|
-
pending_ids = []
|
421
|
-
channels = self.channels if local else self.get_all_channels()
|
422
|
-
for channel in channels:
|
423
|
-
pending_ids.extend(self.get_pending_ids(channel))
|
424
|
-
return pending_ids
|
425
|
-
|
426
|
-
def get_all_running_ids(self, local=False):
|
427
|
-
"""
|
428
|
-
Get all running task IDs across all channels.
|
429
|
-
|
430
|
-
:return: List of all running task IDs.
|
431
|
-
"""
|
432
|
-
running_ids = []
|
433
|
-
channels = self.channels if local else self.get_all_channels()
|
434
|
-
for channel in channels:
|
435
|
-
running_ids.extend(self.get_running_ids(channel))
|
436
|
-
return running_ids
|
437
|
-
|
438
|
-
def get_all_completed_ids(self, local=False):
|
439
|
-
"""
|
440
|
-
Get all completed task IDs across all channels.
|
441
|
-
|
442
|
-
:return: List of all completed task IDs.
|
443
|
-
"""
|
444
|
-
completed_ids = []
|
445
|
-
channels = self.channels if local else self.get_all_channels()
|
446
|
-
for channel in channels:
|
447
|
-
completed_ids.extend(self.get_completed_ids(channel))
|
448
|
-
return completed_ids
|
449
|
-
|
450
|
-
def get_all_error_ids(self, local=False):
|
451
|
-
"""
|
452
|
-
Get all error task IDs across all channels.
|
453
|
-
|
454
|
-
:return: List of all error task IDs.
|
455
|
-
"""
|
456
|
-
error_ids = []
|
457
|
-
channels = self.channels if local else self.get_all_channels()
|
458
|
-
for channel in channels:
|
459
|
-
error_ids.extend(self.get_error_ids(channel))
|
460
|
-
return error_ids
|
461
|
-
|
462
|
-
def get_all_pending(self, include_data=False, local=False):
|
463
|
-
"""
|
464
|
-
Get all pending tasks as objects.
|
465
|
-
|
466
|
-
:return: List of pending task objects.
|
467
|
-
"""
|
468
|
-
pending_tasks = []
|
469
|
-
for task_id in self.get_all_pending_ids(local=local):
|
470
|
-
task = self.get_task(task_id)
|
471
|
-
if task:
|
472
|
-
if not include_data:
|
473
|
-
del task.data
|
474
|
-
pending_tasks.append(task)
|
475
|
-
else:
|
476
|
-
self.remove_from_pending(task_id)
|
477
|
-
return pending_tasks
|
478
|
-
|
479
|
-
def get_all_running(self, include_data=False, local=False):
|
480
|
-
"""
|
481
|
-
Get all running tasks as objects.
|
482
|
-
|
483
|
-
:return: List of running task objects.
|
484
|
-
"""
|
485
|
-
running_tasks = []
|
486
|
-
for task_id in self.get_all_running_ids(local=local):
|
487
|
-
task = self.get_task(task_id)
|
488
|
-
if task:
|
489
|
-
if not include_data:
|
490
|
-
del task.data
|
491
|
-
running_tasks.append(task)
|
492
|
-
else:
|
493
|
-
self.remove_from_running(task_id)
|
494
|
-
return running_tasks
|
495
|
-
|
496
|
-
def get_all_completed(self, include_data=False, local=False):
|
497
|
-
"""
|
498
|
-
Get all completed tasks as objects.
|
499
|
-
|
500
|
-
:return: List of completed task objects.
|
501
|
-
"""
|
502
|
-
completed_tasks = []
|
503
|
-
for task_id in self.get_all_completed_ids(local=local):
|
504
|
-
task = self.get_task(task_id)
|
505
|
-
if task:
|
506
|
-
if not include_data:
|
507
|
-
del task.data
|
508
|
-
completed_tasks.append(task)
|
509
|
-
else:
|
510
|
-
self.remove_from_completed(task_id)
|
511
|
-
# Sort tasks by the created timestamp in descending order
|
512
|
-
completed_tasks.sort(key=lambda x: x.created, reverse=True)
|
513
|
-
return completed_tasks
|
514
|
-
|
515
|
-
def get_all_errors(self, local=False):
|
516
|
-
"""
|
517
|
-
Get all error tasks as objects.
|
518
|
-
|
519
|
-
:return: List of error task objects.
|
520
|
-
"""
|
521
|
-
error_tasks = []
|
522
|
-
for task_id in self.get_all_error_ids(local=local):
|
523
|
-
task = self.get_task(task_id)
|
524
|
-
if task:
|
525
|
-
error_tasks.append(task)
|
526
|
-
else:
|
527
|
-
self.remove_from_errors(task_id)
|
528
|
-
# Sort tasks by the created timestamp in descending order
|
529
|
-
error_tasks.sort(key=lambda x: x.created, reverse=True)
|
530
|
-
return error_tasks
|
531
|
-
|
532
|
-
def get_channel_status(self, channel):
|
533
|
-
status = objict()
|
534
|
-
status.pending = len(self.get_pending_ids(channel))
|
535
|
-
status.running = len(self.get_running_ids(channel))
|
536
|
-
status.completed = len(self.get_completed_ids(channel))
|
537
|
-
status.errors = len(self.get_error_ids(channel))
|
538
|
-
return status
|
539
|
-
|
540
|
-
def get_status(self, simple=False, local=False):
|
541
|
-
"""
|
542
|
-
Get the status of tasks across all channels, including pending and running tasks.
|
543
|
-
|
544
|
-
:return: Status object containing counts of pending and running tasks per channel.
|
545
|
-
"""
|
546
|
-
status = objict(pending=0, running=0, completed=0, errors=0)
|
547
|
-
if not simple:
|
548
|
-
status.channels = objict()
|
549
|
-
channels = self.channels if local else self.get_all_channels()
|
550
|
-
# Use channels from Redis instead of self.channels
|
551
|
-
for channel in channels:
|
552
|
-
cstatus = self.get_channel_status(channel)
|
553
|
-
status.pending += cstatus.pending
|
554
|
-
status.running += cstatus.running
|
555
|
-
status.completed += cstatus.completed
|
556
|
-
status.errors += cstatus.errors
|
557
|
-
if not simple:
|
558
|
-
status.channels[channel] = cstatus
|
559
|
-
status["runners"] = self.get_active_runners()
|
560
|
-
return status
|
561
|
-
|
562
|
-
def get_all_runners(self):
|
563
|
-
"""
|
564
|
-
Get all runners.
|
565
|
-
|
566
|
-
Returns:
|
567
|
-
dict: Dictionary of runners with their status.
|
568
|
-
"""
|
569
|
-
runners = {}
|
570
|
-
raw_runners = self.redis.hgetall(self.get_runners_key())
|
571
|
-
for hostname, data in raw_runners.items():
|
572
|
-
try:
|
573
|
-
runner = objict.from_json(data.decode())
|
574
|
-
runner["ping_age"] = time.time() - runner["last_ping"]
|
575
|
-
if runner["ping_age"] > 30:
|
576
|
-
runner["status"] = "timeout"
|
577
|
-
runners[hostname.decode()] = runner
|
578
|
-
except Exception:
|
579
|
-
continue
|
580
|
-
return runners
|
581
|
-
|
582
|
-
def get_active_runners(self):
|
583
|
-
"""
|
584
|
-
Get all active runners.
|
585
|
-
|
586
|
-
Returns:
|
587
|
-
dict: Dictionary of active runners with their status.
|
588
|
-
"""
|
589
|
-
return self.get_all_runners()
|
590
|
-
|
591
|
-
def remove_runner(self, hostname):
|
592
|
-
"""
|
593
|
-
Remove a runner from the list of active runners.
|
594
|
-
|
595
|
-
Args:
|
596
|
-
hostname (str): The hostname of the runner to remove.
|
597
|
-
"""
|
598
|
-
self.redis.hdel(self.get_runners_key(), hostname)
|
599
|
-
|
600
|
-
def clear_runners(self, ping_age=30):
|
601
|
-
raw_runners = self.get_all_runners()
|
602
|
-
for runner in raw_runners.values():
|
603
|
-
try:
|
604
|
-
runner["ping_age"] = time.time() - runner["last_ping"]
|
605
|
-
if runner["ping_age"] > ping_age:
|
606
|
-
self.remove_runner(runner["hostname"])
|
607
|
-
except Exception:
|
608
|
-
continue
|
609
|
-
|
610
|
-
def clear_running_tasks(self):
|
611
|
-
"""
|
612
|
-
Reset tasks that are stuck in a running state by moving them back to the pending state.
|
613
|
-
"""
|
614
|
-
for channel in self.channels:
|
615
|
-
for task_id in self.get_running_ids(channel):
|
616
|
-
# self.logger.info(f"moving task {task_id} from running to pending")
|
617
|
-
self.remove_from_running(task_id, channel)
|
618
|
-
self.add_to_pending(task_id, channel)
|
619
|
-
|
620
|
-
def clear_pending_tasks(self):
|
621
|
-
"""
|
622
|
-
Reset tasks that are stuck in a pending state by moving them back to the pending state.
|
623
|
-
"""
|
624
|
-
for channel in self.channels:
|
625
|
-
for task_id in self.get_pending_ids(channel):
|
626
|
-
# self.logger.info(f"moving task {task_id} from running to pending")
|
627
|
-
self.remove_from_pending(task_id, channel)
|
628
|
-
|
629
|
-
def clear_channel(self, channel):
|
630
|
-
for task_id in self.get_running_ids(channel):
|
631
|
-
self.remove_from_running(task_id, channel)
|
632
|
-
for task_id in self.get_pending_ids(channel):
|
633
|
-
self.remove_from_pending(task_id, channel)
|
634
|
-
for task_id in self.get_completed_ids(channel):
|
635
|
-
self.remove_from_completed(task_id, channel)
|
636
|
-
for task_id in self.get_error_ids(channel):
|
637
|
-
self.remove_from_errors(task_id, channel)
|
638
|
-
|
639
|
-
def clear_local_queues(self):
|
640
|
-
"""
|
641
|
-
Reset tasks that are stuck in a pending state by moving them back to the pending state.
|
642
|
-
"""
|
643
|
-
for channel in self.channels:
|
644
|
-
self.clear_channel(channel)
|
mojo/apps/tasks/rest/__init__.py
DELETED
mojo/apps/tasks/rest/hooks.py
DELETED
File without changes
|