Skip to content

Commit c3549b3

Browse files
committed
[IMP] Kill workers with SIGABRT before SIGKILL.
This gives long running processes a small window in which to clean up gracefully.
1 parent 4e53ef2 commit c3549b3

File tree

1 file changed

+30
-5
lines changed

1 file changed

+30
-5
lines changed

odoo/service/server.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
#-----------------------------------------------------------
22
# Threaded, Gevent and Prefork Servers
33
#-----------------------------------------------------------
4+
import ctypes
45
import datetime
56
import errno
67
import logging
78
import os
89
import os.path
910
import platform
1011
import random
12+
import requests
1113
import select
1214
import signal
1315
import socket
@@ -826,7 +828,10 @@ def process_timeout(self):
826828
worker.__class__.__name__,
827829
pid,
828830
worker.watchdog_timeout)
829-
self.worker_kill(pid, signal.SIGKILL)
831+
if (now - worker.watchdog_time) >= worker.watchdog_timeout + 5:
832+
self.worker_kill(pid, signal.SIGKILL)
833+
else:
834+
self.worker_kill(pid, signal.SIGABRT)
830835

831836
def process_spawn(self):
832837
if config['http_enable']:
@@ -946,6 +951,7 @@ def __init__(self, multi):
946951
self.ppid = os.getpid()
947952
self.pid = None
948953
self.alive = True
954+
self.thread = None
949955
# should we rename into lifetime ?
950956
self.request_max = multi.limit_request
951957
self.request_count = 0
@@ -969,6 +975,24 @@ def signal_time_expired_handler(self, n, stack):
969975
# We dont suicide in such case
970976
raise Exception('CPU time limit exceeded.')
971977

978+
def signal_time_real_handler(self, sig, frame):
979+
_logger.info('Worker (%d) real time limit (%s) reached.', self.pid, config['limit_time_real'])
980+
thread_id = None
981+
if hasattr(self.thread, '_thread_id'):
982+
thread_id = self.thread._thread_id
983+
for id, thread in threading._active.items():
984+
if thread is self.thread:
985+
thread_id = id
986+
if not thread_id:
987+
raise Exception('Failed to determine thread id.')
988+
989+
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(SystemExit))
990+
if res > 1:
991+
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
992+
# print('Exception raise failure')
993+
994+
# raise Exception('Real time limit exceeded.')
995+
972996
def sleep(self):
973997
try:
974998
select.select([self.multi.socket, self.wakeup_fd_r], [], [], self.multi.beat)
@@ -1017,6 +1041,7 @@ def start(self):
10171041
# reset blocking status
10181042
self.multi.socket.setblocking(0)
10191043

1044+
signal.signal(signal.SIGABRT, self.signal_time_real_handler)
10201045
signal.signal(signal.SIGINT, self.signal_handler)
10211046
signal.signal(signal.SIGXCPU, self.signal_time_expired_handler)
10221047

@@ -1034,10 +1059,10 @@ def stop(self):
10341059
def run(self):
10351060
try:
10361061
self.start()
1037-
t = threading.Thread(name="Worker %s (%s) workthread" % (self.__class__.__name__, self.pid), target=self._runloop)
1038-
t.daemon = True
1039-
t.start()
1040-
t.join()
1062+
self.thread = threading.Thread(name="Worker %s (%s) workthread" % (self.__class__.__name__, self.pid), target=self._runloop)
1063+
self.thread.daemon = True
1064+
self.thread.start()
1065+
self.thread.join()
10411066
_logger.info("Worker (%s) exiting. request_count: %s, registry count: %s.",
10421067
self.pid, self.request_count,
10431068
len(odoo.modules.registry.Registry.registries))

0 commit comments

Comments
 (0)