1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 Threads monitoring service
19 """
20
21 __maintainer__ = "Florian Boucault <florian@fluendo.com>"
22
23 import os, sys
24 import tempfile
25 import traceback
26 import threading
27
28 from elisa.base_components import service_provider
29
30 from twisted.internet import reactor
31
33 """
34 Service checking periodically the current number of threads
35 and giving a warning if a certain limit is reached.
36
37 Warning: this component only takes into account threads created from
38 Python
39 """
40
41 default_config = {'max_threads': '2',
42 'frequency': '1.0'}
43 config_doc = {'max_threads': 'Maximum number of threads at any time.',
44 'frequency': 'Frequency of the monitoring in times per'
45 ' second'}
46
50
52 self._max_threads = int(self.config.get('max_threads'))
53 self._frequency = float(self.config.get('frequency'))
54 self.info("Checking %s times per second that no more than %s threads \
55 are concurrently running", self._frequency, self._max_threads)
56
57 self._delayed = reactor.callLater(1.0/self._frequency, self._check)
58
60 if self._delayed != None and self._delayed.active():
61 reactor.cancelCallLater(self._delayed)
62
64 frames = sys._current_frames()
65
66
67 waiters_count = len(reactor.threadpool.waiters)
68 threads_count = len(frames) - waiters_count
69
70 if threads_count > self._max_threads:
71 fd_log, path = tempfile.mkstemp(prefix="elisa_",
72 suffix="_threads")
73
74 os.write(fd_log, "Stack of concurrent Python threads\n")
75 os.write(fd_log, "==================================\n\n")
76
77 for id, frame in frames.items():
78 try:
79 thread = threading._active[id]
80 except KeyError:
81
82 continue
83
84
85 if thread in reactor.threadpool.waiters:
86 continue
87
88 os.write(fd_log, "%s\n" % thread.getName())
89 stack = traceback.format_stack(frame)
90 for line in stack:
91 os.write(fd_log, line)
92 os.write(fd_log, "\n")
93
94 self.warning("Too many concurrent threads (%s); stacks written at "
95 "%s" % (threads_count, path))
96 os.close(fd_log)
97
98 self._delayed = reactor.callLater(1.0/self._frequency, self._check)
99