Files
tryton/trytond/status.py
T
Cédric Krier 289bd14bbf Do not start status report on platform without AF_UNIX socket
issue11319
review393871002
(grafted from f9c934230c6b1f7d8c5ee4a3722227ced19393ae)

--HG--
branch : 6.0
2022-04-01 23:48:06 +02:00

125 lines
3.1 KiB
Python

# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import json
import logging
import os
import socket
import threading
import time
from collections import namedtuple
from contextlib import contextmanager
status = dict()
logger = logging.getLogger(__name__)
address = 'trytond-stat.socket'
Process = namedtuple('Process', ['start_time', 'request'])
_PID = None
_PATH = None
_LOCK = threading.Lock()
@contextmanager
def processing(request):
start(_PATH) # check if running thread
process = Process(time.perf_counter(), request)
status[id(process)] = process
try:
yield
finally:
status.pop(id(process), None)
def log():
from trytond.cache import Cache
msg = []
now = time.perf_counter()
for process in sorted(status.copy().values(), key=lambda p: p.start_time):
msg.append({
'since': now - process.start_time,
'request': str(process.request),
})
return {
'id': os.getpid(),
'status': msg,
'caches': list(Cache.stats()),
}
def dump(path):
if not hasattr(socket, 'AF_UNIX'):
return False
sock = socket.socket(socket.AF_UNIX)
try:
try:
sock.connect(os.path.join(path, address))
except socket.error:
return False
try:
sock.sendall(json.dumps(log()).encode('utf-8'))
except socket.error:
pass
finally:
sock.close()
return True
def dumper(path):
while True:
if dump(path):
time.sleep(5)
else:
time.sleep(60)
def start(path):
global _PID, _PATH
if not hasattr(socket, 'AF_UNIX'):
return
if _PID != os.getpid() and path: # Quick test without lock
with _LOCK:
if _PID != os.getpid():
threading.Thread(
target=dumper, args=(path,), daemon=True).start()
_PID = os.getpid()
_PATH = path
def listen(path, callback=None):
if not hasattr(socket, 'AF_UNIX'):
return False
sock = socket.socket(socket.AF_UNIX)
socket_file = os.path.join(path, address)
try:
sock.bind(socket_file)
sock.listen(1)
sock.settimeout(5)
while True:
try:
connection, client_address = sock.accept()
except socket.timeout:
if callback:
callback()
continue
try:
data = b''
while True:
chunk = connection.recv(1024)
if not chunk:
break
else:
data += chunk
try:
data = json.loads(data)
except ValueError:
continue
if callback:
callback(data)
finally:
connection.close()
finally:
sock.close()
os.unlink(socket_file)
return True