django-restit 4.2.167__py3-none-any.whl → 4.2.173__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- {django_restit-4.2.167.dist-info → django_restit-4.2.173.dist-info}/METADATA +3 -2
- {django_restit-4.2.167.dist-info → django_restit-4.2.173.dist-info}/RECORD +8 -8
- {django_restit-4.2.167.dist-info → django_restit-4.2.173.dist-info}/WHEEL +1 -1
- metrics/models.py +3 -0
- rest/__init__.py +1 -1
- taskqueue/models.py +7 -11
- taskqueue/worker.py +70 -47
- {django_restit-4.2.167.dist-info → django_restit-4.2.173.dist-info}/LICENSE.md +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: django-restit
|
3
|
-
Version: 4.2.
|
3
|
+
Version: 4.2.173
|
4
4
|
Summary: A Rest Framework for DJANGO
|
5
5
|
License: MIT
|
6
6
|
Author: Ian Starnes
|
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.10
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
16
17
|
Requires-Dist: boto3 (>=1.26.160,<2.0.0)
|
17
18
|
Requires-Dist: django
|
18
19
|
Requires-Dist: django-redis-cache (>=3.0.1,<4.0.0)
|
@@ -356,7 +356,7 @@ metrics/migrations/0003_metrics_expires.py,sha256=_g4oRv4NHW-4iCQx2s1SiF38LLyFf8
|
|
356
356
|
metrics/migrations/0004_eodmetrics.py,sha256=Ky6ZVMZqa0F_SUp_QFWY7ZKBgVhy9CS4wZcsEhrkSgc,3271
|
357
357
|
metrics/migrations/0005_alter_metrics_v1_alter_metrics_v10_alter_metrics_v11_and_more.py,sha256=pmwJfpPJ1RUX_CqM66l6vvV-nrAUPo_GIan0Pc9mQHs,2358
|
358
358
|
metrics/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
359
|
-
metrics/models.py,sha256
|
359
|
+
metrics/models.py,sha256=O29Cud4VAwIAWnmQymFti0-ibOEoGmTWGxWsbtzcZHQ,14162
|
360
360
|
metrics/periodic.py,sha256=IayBLLat40D8FB-A3bYBW9lxm9-IzcugQunojThQ_OU,661
|
361
361
|
metrics/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
362
362
|
metrics/providers/aws.py,sha256=dIBGFE1Fvszy6rmVrn_Fm1zUDv345q4dBsg9Iit-XCc,8358
|
@@ -379,7 +379,7 @@ pushit/utils.py,sha256=IeTCGa-164nmB1jIsK1lu1O1QzUhS3BKfuXHGjCW-ck,2121
|
|
379
379
|
rest/.gitignore,sha256=TbEvWRMnAiajCTOdhiNrd9eeCAaIjRp9PRjE_VkMM5g,118
|
380
380
|
rest/README.md,sha256=V3ETc-cJu8PZIbKr9xSe_pA4JEUpC8Dhw4bQeVCDJPw,5460
|
381
381
|
rest/RemoteEvents.py,sha256=nL46U7AuxIrlw2JunphR1tsXyqi-ep_gD9CYGpYbNgE,72
|
382
|
-
rest/__init__.py,sha256=
|
382
|
+
rest/__init__.py,sha256=X-ZjYMsIpHcsnYPqEyCUT_cVtex5VAn-DlgZF8JJFg0,122
|
383
383
|
rest/arc4.py,sha256=y644IbF1ec--e4cUJ3KEYsewTCITK0gmlwa5mJruFC0,1967
|
384
384
|
rest/cache.py,sha256=1Qg0rkaCJCaVP0-l5hZg2CIblTdeBSlj_0fP6vlKUpU,83
|
385
385
|
rest/crypto/__init__.py,sha256=Tl0U11rgj1eBYqd6OXJ2_XSdNLumW_JkBZnaJqI6Ldw,72
|
@@ -461,7 +461,7 @@ taskqueue/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
461
461
|
taskqueue/admin.py,sha256=E6zXoToS_ea3MdoGjZzF1JiepWFtDSoZUQdan8H-pXI,208
|
462
462
|
taskqueue/migrations/0001_initial.py,sha256=JwYib8CK5ftSXlfxKZUcKEEVsXktNB5q3h-2tu9inGk,4738
|
463
463
|
taskqueue/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
464
|
-
taskqueue/models.py,sha256=
|
464
|
+
taskqueue/models.py,sha256=XqgQDKaxKAfqSkom0VF2HeUwFXpvM46ikZdvKXUKAz8,23843
|
465
465
|
taskqueue/periodic.py,sha256=hpXnunJL_cuVQLAKpjTbABbsQ4fvdsV9_gyyK-_53Sk,3844
|
466
466
|
taskqueue/rpc.py,sha256=Lf5VUoqCRkfWUAIvx_s508mjAtDPwpiWyxg0ryqWbQA,5793
|
467
467
|
taskqueue/tq.py,sha256=PzSoDrawYcqZylruEgsK95gcJ4J_VhdM6rxg9V6_X8E,942
|
@@ -471,7 +471,7 @@ taskqueue/transports/http.py,sha256=AzliUnw_LuyO2zZZOoUAJGFcTV-Gxt1iE3hCVnIiyGQ,
|
|
471
471
|
taskqueue/transports/s3.py,sha256=fMosL893u1iQdo6Y1djwb7KEoNo6TTsDPJl13OJdJP8,1913
|
472
472
|
taskqueue/transports/sftp.py,sha256=jT1_krjTHA7DCAukD85aGYRCg9m0cEH9EWzOC-wJGdk,1891
|
473
473
|
taskqueue/transports/sms.py,sha256=H1-LIGEMfbUNqJD9amRcsvKUSwtz9yBj1QNfB7EHjHE,142
|
474
|
-
taskqueue/worker.py,sha256=
|
474
|
+
taskqueue/worker.py,sha256=91n_GuwB-keozkyrgYcDpFUybV6EC2Yirnv8owPUwrg,16250
|
475
475
|
telephony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
476
476
|
telephony/admin.py,sha256=iOdsBfFFbBisdqKSZ36bIrh_z5sU0Wx_PkaFi8wd1iA,243
|
477
477
|
telephony/decorators.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -515,7 +515,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
|
|
515
515
|
ws4redis/settings.py,sha256=KKq00EwoGnz1yLwCZr5Dfoq2izivmAdsNEEM4EhZwN4,1610
|
516
516
|
ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
|
517
517
|
ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
|
518
|
-
django_restit-4.2.
|
519
|
-
django_restit-4.2.
|
520
|
-
django_restit-4.2.
|
521
|
-
django_restit-4.2.
|
518
|
+
django_restit-4.2.173.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
|
519
|
+
django_restit-4.2.173.dist-info/METADATA,sha256=i08Bup9bGciei5ZmKtc-1LMW236KZYtfSWUByHv6tfo,7714
|
520
|
+
django_restit-4.2.173.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
521
|
+
django_restit-4.2.173.dist-info/RECORD,,
|
metrics/models.py
CHANGED
@@ -40,6 +40,8 @@ def metric(
|
|
40
40
|
expires = datetime.now() + timedelta(days=METRICS_EXPIRE_DAILY)
|
41
41
|
elif granularity == "weekly":
|
42
42
|
expires = datetime.now() + timedelta(days=METRICS_EXPIRE_WEEKLY)
|
43
|
+
elif granularity in ["minutes", "seconds"]:
|
44
|
+
expires = datetime.now() + timedelta(days=7)
|
43
45
|
m, created = Metrics.objects.get_or_create(
|
44
46
|
uuid=key,
|
45
47
|
defaults=dict(
|
@@ -88,6 +90,7 @@ def normalize_date(date=None, timezone=None, group=None):
|
|
88
90
|
date = date_util.convertToLocalTime(settings.METRICS_TIMEZONE, date)
|
89
91
|
return date
|
90
92
|
|
93
|
+
|
91
94
|
def get_qset(slug, granularity, start=None, end=None,
|
92
95
|
group=-1, starts_with=False, ends_with=None):
|
93
96
|
if start is None:
|
rest/__init__.py
CHANGED
taskqueue/models.py
CHANGED
@@ -166,8 +166,8 @@ class Task(models.Model, RestModel):
|
|
166
166
|
self.retry_now()
|
167
167
|
elif value == "cancel":
|
168
168
|
request = self.getActiveRequest()
|
169
|
-
self.reason = "cancel request by {
|
170
|
-
self.cancel(request.DATA.get("reason", "canceled by {
|
169
|
+
self.reason = f"cancel request by {request.member.username}"
|
170
|
+
self.cancel(request.DATA.get("reason", f"canceled by {request.member.username}"))
|
171
171
|
|
172
172
|
# def auditlog(self, action, message, request=None, path=None, component="taskqueue.Task"):
|
173
173
|
# # message, level=0, request=None, component=None, pkey=None, action=None, group=None, path=None, method=None
|
@@ -183,7 +183,7 @@ class Task(models.Model, RestModel):
|
|
183
183
|
level = 21
|
184
184
|
elif kind == "error":
|
185
185
|
level = 17
|
186
|
-
PLOG.log(message=text, action=f"taskqueue_{kind}",
|
186
|
+
PLOG.log(message=text, action=f"taskqueue_{kind}",
|
187
187
|
level=level,
|
188
188
|
method=self.fname, path=self.model,
|
189
189
|
tid=self.data.log_tid,
|
@@ -290,7 +290,7 @@ class Task(models.Model, RestModel):
|
|
290
290
|
try:
|
291
291
|
import incident
|
292
292
|
incident.event_now(
|
293
|
-
category, description=subject, details=msg,
|
293
|
+
category, description=subject, details=msg,
|
294
294
|
level=3, **metadata)
|
295
295
|
except Exception as err:
|
296
296
|
self.log(str(err), kind="error")
|
@@ -395,7 +395,7 @@ class Task(models.Model, RestModel):
|
|
395
395
|
task.save()
|
396
396
|
task.publish()
|
397
397
|
return task
|
398
|
-
|
398
|
+
|
399
399
|
@classmethod
|
400
400
|
def S3Request(cls, bucket, data, folder, aws, secret, filename, when,
|
401
401
|
log_component=None, log_pk=None, log_tid=None):
|
@@ -458,7 +458,6 @@ class TaskWorkerClient:
|
|
458
458
|
uid = crypto.randomString(16)
|
459
459
|
self.recv_channel = f"tq:{uid}:{settings.HOSTNAME}"
|
460
460
|
self.send_channel = f"tq:host:{hostname}"
|
461
|
-
|
462
461
|
self.client = None
|
463
462
|
self.pubsub = None
|
464
463
|
|
@@ -480,7 +479,7 @@ class TaskWorkerClient:
|
|
480
479
|
data["hostname"] = settings.HOSTNAME
|
481
480
|
data["response_channel"] = self.recv_channel
|
482
481
|
redis.publish(
|
483
|
-
self.send_channel,
|
482
|
+
self.send_channel,
|
484
483
|
data, self.client)
|
485
484
|
|
486
485
|
def recv(self, timeout=5.0):
|
@@ -492,7 +491,7 @@ class TaskWorkerClient:
|
|
492
491
|
if msg.data:
|
493
492
|
msg.data = nobjict.fromJSON(msg.data)
|
494
493
|
return msg.data
|
495
|
-
|
494
|
+
|
496
495
|
def ping(self):
|
497
496
|
start = time.perf_counter()
|
498
497
|
self.send(dict(action="ping"))
|
@@ -644,6 +643,3 @@ class TaskHook(models.Model, RestModel, MetaDataModel):
|
|
644
643
|
|
645
644
|
class TaskHookMetaData(MetaDataBase):
|
646
645
|
parent = models.ForeignKey(TaskHook, related_name="properties", on_delete=models.CASCADE)
|
647
|
-
|
648
|
-
|
649
|
-
|
taskqueue/worker.py
CHANGED
@@ -62,7 +62,7 @@ class WorkManager(object):
|
|
62
62
|
task.failed("stale")
|
63
63
|
return
|
64
64
|
if task.id in self._scheduled_tasks:
|
65
|
-
self.logger.error("task({}) is
|
65
|
+
self.logger.error("task({}) is already scheduled".format(task.id))
|
66
66
|
return
|
67
67
|
task.manager = self
|
68
68
|
with self.lock:
|
@@ -84,10 +84,10 @@ class WorkManager(object):
|
|
84
84
|
if event.channel == "tq_restart":
|
85
85
|
self.restart()
|
86
86
|
return
|
87
|
-
|
87
|
+
|
88
88
|
if event.data:
|
89
89
|
event.data = nobjict.fromJSON(event.data)
|
90
|
-
|
90
|
+
|
91
91
|
if event.channel == self.host_channel:
|
92
92
|
self.on_host_event(event)
|
93
93
|
return
|
@@ -198,6 +198,7 @@ class WorkManager(object):
|
|
198
198
|
task.failed("max attempts")
|
199
199
|
|
200
200
|
def _on_hookrequest(self, task):
|
201
|
+
resp = None
|
201
202
|
if task.model == "tq_email_request":
|
202
203
|
resp = email.SEND(task)
|
203
204
|
elif task.model == "tq_sms_request":
|
@@ -223,7 +224,7 @@ class WorkManager(object):
|
|
223
224
|
redis.publish(
|
224
225
|
event.data.response_channel,
|
225
226
|
dict(action="restarting", hostname=settings.HOSTNAME))
|
226
|
-
self.restart()
|
227
|
+
self.restart()
|
227
228
|
elif action == "get_stats":
|
228
229
|
data = nobjict(action="stats", hostname=settings.HOSTNAME)
|
229
230
|
data.uptime = time.time() - self.started_at
|
@@ -240,83 +241,107 @@ class WorkManager(object):
|
|
240
241
|
task.worker_running = True
|
241
242
|
self._running_count += 1
|
242
243
|
self._pending_count -= 1
|
244
|
+
# remove the task from scheduled
|
245
|
+
del self._scheduled_tasks[task.id]
|
243
246
|
self.updateCounts()
|
244
247
|
|
245
248
|
def on_task_ended(self, task):
|
246
249
|
with self.lock:
|
247
250
|
task.worker_running = False
|
248
|
-
del self._scheduled_tasks[task.id]
|
249
251
|
self._running_count -= 1
|
250
252
|
self.updateCounts()
|
251
253
|
|
252
254
|
def on_run_task(self, task):
|
255
|
+
""" Handles execution of a task with structured error handling and refactored logic. """
|
256
|
+
|
253
257
|
self.logger.info("running task({})".format(task.id))
|
254
258
|
|
255
|
-
#
|
259
|
+
# Start task and handle cancel/stale conditions early
|
260
|
+
if not self._initialize_task(task):
|
261
|
+
return
|
262
|
+
|
263
|
+
# Get the appropriate handler for the task
|
264
|
+
handler = self._get_task_handler(task)
|
265
|
+
if handler is None:
|
266
|
+
task.failed("failed to find handler")
|
267
|
+
return self._end_task(task)
|
268
|
+
|
269
|
+
# Execute task
|
270
|
+
self._execute_task(task, handler)
|
271
|
+
|
272
|
+
def _initialize_task(self, task):
|
273
|
+
""" Initializes task and checks if it should run. Returns False if the task should stop. """
|
256
274
|
try:
|
257
275
|
self.on_task_started(task)
|
258
276
|
task.refresh_from_db()
|
259
277
|
task._thread_id = threading.current_thread().ident
|
260
278
|
self.logger.debug("running on thread:{}".format(task._thread_id))
|
279
|
+
|
261
280
|
if task.state not in [0, 1, 2, 10] or task.cancel_requested:
|
262
281
|
self.logger.info("task({}) was canceled?".format(task.id))
|
263
|
-
self.
|
264
|
-
return
|
282
|
+
return self._end_task(task)
|
265
283
|
|
266
284
|
if task.is_stale:
|
267
285
|
self.logger.warning("task({}) is now stale".format(task.id))
|
268
286
|
task.failed("stale")
|
269
|
-
self.
|
270
|
-
|
287
|
+
return self._end_task(task)
|
288
|
+
|
289
|
+
return True
|
271
290
|
except Exception as err:
|
272
291
|
self.logger.exception(err)
|
273
|
-
return
|
292
|
+
return False
|
274
293
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
self.logger.exception(err)
|
285
|
-
task.log_exception(err)
|
286
|
-
task.failed(str(err))
|
287
|
-
self.on_task_ended(task)
|
288
|
-
return
|
294
|
+
def _get_task_handler(self, task):
|
295
|
+
""" Determines the appropriate handler for the task. """
|
296
|
+
task_handlers = {
|
297
|
+
"tq_web_request": self._on_webrequest,
|
298
|
+
"tq_sftp_request": self._on_hookrequest,
|
299
|
+
"tq_email_request": self._on_hookrequest,
|
300
|
+
"tq_sms_request": self._on_hookrequest,
|
301
|
+
"tq_s3_request": self._on_hookrequest,
|
302
|
+
}
|
289
303
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
304
|
+
handler = task_handlers.get(task.model)
|
305
|
+
if handler:
|
306
|
+
return handler
|
307
|
+
|
308
|
+
try:
|
309
|
+
return task.getHandler()
|
310
|
+
except Exception as err:
|
311
|
+
self.logger.exception(err)
|
312
|
+
task.log_exception(err)
|
313
|
+
task.failed(str(err))
|
314
|
+
self._end_task(task)
|
315
|
+
return None
|
295
316
|
|
296
|
-
|
317
|
+
def _execute_task(self, task, handler):
|
318
|
+
""" Runs the task handler and manages exceptions. """
|
297
319
|
task.started()
|
298
320
|
try:
|
299
|
-
# self.logger.debug("task({}) calling handler".format(task.id))
|
300
321
|
handler(task)
|
301
322
|
if task.state == TASK_STATE_STARTED:
|
302
323
|
task.completed()
|
303
|
-
# self.logger.debug("task({}) handler finished".format(task.id))
|
304
324
|
except Exception as err:
|
305
|
-
self.
|
306
|
-
task.log_exception(err)
|
307
|
-
if "connection already closed" in str(err).lower():
|
308
|
-
# this is a nasty little bug in django when forking django db connections
|
309
|
-
# we will schedule the task to retry later
|
310
|
-
task.retry_later()
|
311
|
-
# let us try and close db connections?
|
312
|
-
hack_closeDjangoDB()
|
313
|
-
# or should we restart the task queue?
|
314
|
-
else:
|
315
|
-
task.failed(str(err))
|
325
|
+
self._handle_task_exception(task, err)
|
316
326
|
except SystemExit:
|
317
327
|
self.logger.error("task({}) was killed".format(task.id))
|
318
328
|
finally:
|
319
|
-
self.
|
329
|
+
self._end_task(task)
|
330
|
+
|
331
|
+
def _handle_task_exception(self, task, err):
|
332
|
+
""" Handles exceptions during task execution. """
|
333
|
+
self.logger.exception("task({}) had exception: {}".format(task.id, err))
|
334
|
+
task.log_exception(err)
|
335
|
+
|
336
|
+
if "connection already closed" in str(err).lower():
|
337
|
+
task.retry_later()
|
338
|
+
hack_closeDjangoDB()
|
339
|
+
else:
|
340
|
+
task.failed(str(err))
|
341
|
+
|
342
|
+
def _end_task(self, task):
|
343
|
+
""" Ensures proper cleanup and logging at the end of the task. """
|
344
|
+
self.on_task_ended(task)
|
320
345
|
self.logger.info("task({}) finished with state {}".format(task.id, task.state))
|
321
346
|
|
322
347
|
def run_forever(self):
|
@@ -420,5 +445,3 @@ def hack_closeDjangoDB():
|
|
420
445
|
from django.db import connections
|
421
446
|
for conn in connections.all():
|
422
447
|
conn.close_if_unusable_or_obsolete()
|
423
|
-
|
424
|
-
|
File without changes
|