django-botmanager 0.2.22__py3-none-any.whl → 0.2.23__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.
@@ -3,9 +3,10 @@ import importlib
3
3
  import json
4
4
  import logging
5
5
  import os
6
+ import signal
6
7
  import sys
7
8
  from datetime import datetime, timedelta
8
- from multiprocessing import Queue, Process
9
+ from multiprocessing import Queue, Process, Event
9
10
  from time import sleep, time
10
11
 
11
12
  import psutil
@@ -30,6 +31,9 @@ except ImportError:
30
31
  setproctitle = lambda x: x
31
32
 
32
33
 
34
+ PROCESS_TO_FINISH_GRACEFULLY_TIMEOUT = 30 # seconds
35
+
36
+
33
37
  class BotManagerCommandException(BotManagerBaseCommandException):
34
38
  pass
35
39
 
@@ -142,7 +146,30 @@ class Command(BotManagerBaseCommand):
142
146
  current_pid = os.getpid()
143
147
  PidsFileController.add_pid(current_pid)
144
148
 
149
+ shutdown_event = Event()
150
+
145
151
  processes = []
152
+
153
+ def signal_handler(signum, frame):
154
+ logging.info('Main process received signal {}'.format(signum))
155
+ logging.info('Start shutting down children processes gracefully...')
156
+ shutdown_event.set()
157
+
158
+ # Wait for processes to finish
159
+ for p in processes:
160
+ p.join(timeout=PROCESS_TO_FINISH_GRACEFULLY_TIMEOUT)
161
+ if p.is_alive():
162
+ logging.info("Process {} didn't terminate gracefully, forcing...".format(p.pid))
163
+ p.terminate()
164
+
165
+ logging.info("All children processes have been terminated. Exiting main process {}.".format(current_pid))
166
+
167
+ sys.exit(0)
168
+
169
+ # Register signal handlers
170
+ signal.signal(signal.SIGTERM, signal_handler)
171
+ signal.signal(signal.SIGINT, signal_handler)
172
+
146
173
  queue_dict = {}
147
174
  for task_class_string, processes_count in self.config['tasks'].items():
148
175
  cls_name = task_class_string.split('.')[-1]
@@ -158,7 +185,7 @@ class Command(BotManagerBaseCommand):
158
185
  queue_dict[task_class.name].maxsize = maxsize
159
186
 
160
187
  for i in range(processes_count):
161
- tm = TaskManager(task_class, queue_dict[task_class.name], i + 1, current_pid)
188
+ tm = TaskManager(task_class, queue_dict[task_class.name], i + 1, current_pid, shutdown_event=shutdown_event)
162
189
  p = Process(target=Command.start_service, args=(tm,))
163
190
  p.name = tm.process_name
164
191
  p.daemon = True
@@ -166,7 +193,7 @@ class Command(BotManagerBaseCommand):
166
193
  processes.append(p)
167
194
  PidsFileController.add_pid(p.pid)
168
195
 
169
- tf = TaskFetcher(queue_dict, current_pid)
196
+ tf = TaskFetcher(queue_dict, current_pid, shutdown_event=shutdown_event)
170
197
  p = Process(target=Command.start_service, args=(tf,))
171
198
  p.name = tf.process_name
172
199
  p.daemon = True
@@ -175,7 +202,7 @@ class Command(BotManagerBaseCommand):
175
202
  PidsFileController.add_pid(p.pid)
176
203
 
177
204
  if not options.get('without_sheduller'):
178
- ts = TaskSheduler(self.config, current_pid)
205
+ ts = TaskSheduler(self.config, current_pid, shutdown_event=shutdown_event)
179
206
  p = Process(target=Command.start_service, args=(ts,))
180
207
  p.name = ts.process_name
181
208
  p.daemon = True
@@ -234,16 +261,16 @@ class Command(BotManagerBaseCommand):
234
261
  class TaskSheduler(object):
235
262
  SET_PERIOD_SECONDS = 5
236
263
 
237
- def __init__(self, config, parent_pid):
264
+ def __init__(self, config, parent_pid, shutdown_event=None):
238
265
  self.process_name = "BotManager.TaskSheduler"
239
266
  self.config = config
240
267
  self.parent_pid = parent_pid
241
268
  self.shedule_cache = {}
269
+ self.shutdown_event = shutdown_event
242
270
 
243
271
  def run(self):
244
272
  setproctitle(self.process_name)
245
- while True:
246
-
273
+ while not self.shutdown_event.is_set():
247
274
  if os.getppid() != self.parent_pid:
248
275
  logging.info(u"Parent process is die. Exit..")
249
276
  break
@@ -259,6 +286,7 @@ class TaskSheduler(object):
259
286
  logging.exception(e)
260
287
 
261
288
  sleep(self.SET_PERIOD_SECONDS)
289
+ logging.info(u"TaskSheduler process shutdown gracefully.")
262
290
 
263
291
  def _time_to_set_tasks_for(self, task_class):
264
292
  last_shedule_time = self.shedule_cache.get(task_class.name)
@@ -268,11 +296,12 @@ class TaskSheduler(object):
268
296
 
269
297
  class TaskFetcher(object):
270
298
 
271
- def __init__(self, queue_dict, parent_pid):
299
+ def __init__(self, queue_dict, parent_pid, shutdown_event=None):
272
300
  self.process_name = "BotManager.TaskFetcher"
273
301
  self.queue_dict = queue_dict
274
302
  self.parent_pid = parent_pid
275
303
  self.config = settings.MAIN_CONFIG
304
+ self.shutdown_event = shutdown_event
276
305
 
277
306
  def run(self):
278
307
  """
@@ -289,7 +318,7 @@ class TaskFetcher(object):
289
318
  """
290
319
  setproctitle(self.process_name)
291
320
  Task.objects.filter(in_process=True).update(in_process=False)
292
- while True:
321
+ while not self.shutdown_event.is_set():
293
322
  try:
294
323
 
295
324
  if os.getppid() != self.parent_pid:
@@ -341,6 +370,8 @@ class TaskFetcher(object):
341
370
 
342
371
  sleep(self.config['fetch_period'])
343
372
 
373
+ logging.info(u"TaskFetcher shutdown gracefully.")
374
+
344
375
  def _get_qsize(self, task):
345
376
  try:
346
377
  return self.queue_dict[task.name].qsize()
@@ -351,12 +382,13 @@ class TaskFetcher(object):
351
382
 
352
383
 
353
384
  class TaskManager(object):
354
- def __init__(self, task_class, queue, process_num, parent_pid):
385
+ def __init__(self, task_class, queue, process_num, parent_pid, shutdown_event=None):
355
386
  self.task_class = task_class
356
387
  self.queue = queue
357
388
  self.process_num = process_num
358
389
  self.process_name = u"BotManager.{0}.{1}".format(self.task_class.name, self.process_num)
359
390
  self.parent_pid = parent_pid
391
+ self.shutdown_event = shutdown_event
360
392
 
361
393
  def __str__(self):
362
394
  return self.process_name
@@ -367,7 +399,7 @@ class TaskManager(object):
367
399
 
368
400
  def run(self):
369
401
  setproctitle(self.process_name)
370
- while True:
402
+ while not self.shutdown_event.is_set():
371
403
  try:
372
404
 
373
405
  if os.getppid() != self.parent_pid:
@@ -390,6 +422,8 @@ class TaskManager(object):
390
422
  u"Error in queue preparing: %s".format(e)
391
423
  )
392
424
 
425
+ logging.info(u"TaskManager process {} shutdown gracefully.".format(self.process_name))
426
+
393
427
 
394
428
  class PidsFileController(object):
395
429
  def __init__(self):
@@ -458,4 +492,3 @@ class PidsFileController(object):
458
492
 
459
493
  if os.path.exists(pids_file_name):
460
494
  os.remove(pids_file_name)
461
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-botmanager
3
- Version: 0.2.22
3
+ Version: 0.2.23
4
4
  Summary: Async tasks for django
5
5
  Home-page: https://github.com/dimoha/django-botmanager
6
6
  Author: Dimoha
@@ -7,7 +7,7 @@ botmanager/settings.py,sha256=saOAublzj8ikIwZ7eJR_P90nKolAv29Kp36QDUYEbbw,3266
7
7
  botmanager/utils.py,sha256=4epNJDf5C7MrNQlZ8t2EAKGsFGRc2uXqoY49__YHGjg,1105
8
8
  botmanager/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  botmanager/management/commands/__init__.py,sha256=uLLxNF6CEdNFFvWTcPHlaYxKQLscMRHs9sRegH19L2g,542
10
- botmanager/management/commands/bot_manager.py,sha256=0443GJ-74DhXTKUDYNY2YL0FQsQChcdk6J0EI8GIoFw,18210
10
+ botmanager/management/commands/bot_manager.py,sha256=WUybgNhLKOkq40LhMZSjMkWDGI8bMPTS6qBmsya6YNo,19749
11
11
  botmanager/migrations/0001_initial.py,sha256=AfYbVMcP171RefENIDUpPkVYQK3xoSxxc_XAr5DIoQs,3357
12
12
  botmanager/migrations/0002_auto_20161208_1406.py,sha256=jxfewdTeJ8RpLl-lzxp1zYtJijVPYR54pPXysJeb62U,742
13
13
  botmanager/migrations/0003_auto_20161208_1529.py,sha256=FMu3GdUsKqR8oPUPxqsqPfRBjVn-9p_wukgHjsFf5hk,1935
@@ -21,8 +21,8 @@ botmanager/migrations/0010_auto_20170531_1321.py,sha256=VnfOWMBI_fuBGmH1NOuXzA5k
21
21
  botmanager/migrations/0011_alter_task_create_dt_alter_task_id.py,sha256=-bR0dQFj_ncNKJLQSVF_aDLIYNkNzkbFcsyWF6vMB2w,706
22
22
  botmanager/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  botmanager/templates/botmanager/task/change_form.html,sha256=kwcZ72z_YgNJgWOKNE_jS1WXk7YDvo50r0kdLBXLhmU,277
24
- django_botmanager-0.2.22.dist-info/licenses/LICENSE,sha256=drrREcwMWVwKpmlpyKh6ytsBFonOm2GbADAJD3WzjKY,1479
25
- django_botmanager-0.2.22.dist-info/METADATA,sha256=PUXCRGRXCK5PDzO6ygyw8BDp3wx6cThKVU1jVKXliD0,439
26
- django_botmanager-0.2.22.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- django_botmanager-0.2.22.dist-info/top_level.txt,sha256=gq7opmRFT7PQifLHi-_hCCtsMjAAiH87radGZ13utgM,11
28
- django_botmanager-0.2.22.dist-info/RECORD,,
24
+ django_botmanager-0.2.23.dist-info/licenses/LICENSE,sha256=drrREcwMWVwKpmlpyKh6ytsBFonOm2GbADAJD3WzjKY,1479
25
+ django_botmanager-0.2.23.dist-info/METADATA,sha256=WBTwZp7r9xc17EZTBuYdYnFyPsCtrnKzwzIVtk7It3E,439
26
+ django_botmanager-0.2.23.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ django_botmanager-0.2.23.dist-info/top_level.txt,sha256=gq7opmRFT7PQifLHi-_hCCtsMjAAiH87radGZ13utgM,11
28
+ django_botmanager-0.2.23.dist-info/RECORD,,