fix threading (!?) plz test

This commit is contained in:
Armin 2026-06-19 17:16:09 +02:00
commit 475426cbe3
6 changed files with 56 additions and 39 deletions

View file

@ -6,11 +6,10 @@
**Because people are asking... Linspector is actually more some kind of a research project for evaluating stuff, but a lot of the code is used in some private projects. I am working on the API definition mostly and there is a lot of code that must be refactored/rewrited ASAP. (2023.11.29)**
**Linspector is currently not process safe because of the GIL! I am refactoring a lot of stuff
at the moment. When running the scheduler in thread-mode everything is fine, but I really want to make it possible to run Linspector using the process-mode of APScheduler...**
**THE CORE NEEDS A REDESIGN AND PARTLY REWRITE TO BE FULLY PROCESS SAFE! I AM WORKING ON THIS
NOW. THE CONFIGURATION INTERFACE WILL NOT BE CHANGED! (2023.10.22)**
**Linspector is now thread-safe in scheduler thread-mode. Shared mutable state (Environment,
Monitor error counts) is protected by locks and the scheduler starts after daemonization to
avoid fork-with-threads issues. Process-mode (multi-process) is still not supported — that
requires a larger architectural redesign with serializable state and IPC.**
## About

View file

@ -194,6 +194,7 @@ def linspector():
log.critical('daemon error: {0}'.format(err))
sys.exit(1)
else:
linspector.start()
try:
signal.pause()
except KeyboardInterrupt:

View file

@ -4,6 +4,9 @@ Copyright (c) 2013-2023 Johannes Findeisen <you@hanez.org>. All Rights Reserved.
See LICENSE.
"""
import threading
class Environment:
"""
Object for storing environment variables at runtime. These variables must not affect the
@ -12,9 +15,11 @@ class Environment:
def __init__(self, log):
self._env = {}
self._lock = threading.Lock()
self._log = log
def get_env_var(self, key):
with self._lock:
if key in self._env:
return self._env[key]
else:
@ -31,7 +36,8 @@ class Environment:
return None
def set_env_var(self, key, value):
if self._env[key]:
with self._lock:
if self._env.get(key):
self._log('warning', __name__, 'environment var "' + key +
' existed and was overwritten!')

View file

@ -35,6 +35,7 @@ class Linspector:
self._plugin_list = []
self._plugins = plugins
self._scheduler = scheduler
self._started = False
# load plugins
if configuration.get_option('linspector', 'plugins'):
@ -145,5 +146,8 @@ class Linspector:
print('Number of scheduled monitors: ' + str(monitor_count))
if configuration.get_option('linspector', 'start_scheduler') == 'true':
def start(self):
if not self._started and \
self._configuration.get_option('linspector', 'start_scheduler') == 'true':
self._scheduler['linspector'].start()
self._started = True

View file

@ -88,6 +88,8 @@ class Linspectord:
# start the daemon.
self.daemonize()
# start scheduler after fork to avoid threading issues
self._linspector.start()
self.run()
def stop(self):

View file

@ -6,6 +6,7 @@ See LICENSE.
import configparser
import importlib
import threading
import time
@ -17,6 +18,7 @@ class Monitor:
self._enabled = True
self._environment = environment
self._error_count = 0
self._lock = threading.Lock()
self._host = monitor_configuration.get('monitor', 'host')
try:
@ -123,12 +125,15 @@ class Monitor:
self._service, **self._args)
notification_error_mode = 'decrease'
with self._lock:
if self._result['status'] == 'ERROR':
self._error_count += 1
elif self._result['status'] == 'OK':
if self._configuration.get_option('linspector', 'notification_error_mode'):
if self._configuration.get_option('linspector',
'notification_error_mode'):
configuration_notification_error_mode = (
self._configuration.get_option('linspector', 'notification_error_mode'))
self._configuration.get_option('linspector',
'notification_error_mode'))
if (configuration_notification_error_mode == 'decrease' or
configuration_notification_error_mode == 'reset'):
notification_error_mode = (