Multithreading #66 (#76)

* feat(multihreading): each url has it's own thread

* Fixing broken unit tests

* Improving readability when there are multiple URLs registerd and creating new action to upload metrics

* Improving error message when there's no file found

* Bumping the version

Co-authored-by: Alex Berenshtein <aberenshtein@yotpo.com>
This commit is contained in:
mtakaki
2020-01-05 10:25:06 -08:00
committed by GitHub
parent 9a73063a6f
commit a13a42d51c
7 changed files with 188 additions and 116 deletions

View File

@@ -1,12 +1,16 @@
#!/usr/bin/env python
import logging
import sys
import threading
import time
import schedule
from yaml import load, SafeLoader
from cachet_url_monitor.configuration import Configuration
cachet_mandatory_fields = ['api_url', 'token']
class Agent(object):
"""Monitor agent that will be constantly verifying if the URL is healthy
@@ -32,7 +36,7 @@ class Agent(object):
def start(self):
"""Sets up the schedule based on the configuration file."""
schedule.every(self.configuration.data['frequency']).seconds.do(self.execute)
schedule.every(self.configuration.endpoint['frequency']).seconds.do(self.execute)
class Decorator(object):
@@ -50,10 +54,15 @@ class CreateIncidentDecorator(Decorator):
configuration.push_incident()
class PushMetricsDecorator(Decorator):
def execute(self, configuration):
configuration.push_metrics()
class Scheduler(object):
def __init__(self, config_file):
def __init__(self, config_file, endpoint_index):
self.logger = logging.getLogger('cachet_url_monitor.scheduler.Scheduler')
self.configuration = Configuration(config_file)
self.configuration = Configuration(config_file, endpoint_index)
self.agent = self.get_agent()
self.stop = False
@@ -62,10 +71,11 @@ class Scheduler(object):
action_names = {
'CREATE_INCIDENT': CreateIncidentDecorator,
'UPDATE_STATUS': UpdateStatusDecorator,
'PUSH_METRICS': PushMetricsDecorator,
}
actions = []
for action in self.configuration.get_action():
self.logger.info('Registering action %s' % (action))
self.logger.info(f'Registering action {action}')
actions.append(action_names[action]())
return Agent(self.configuration, decorators=actions)
@@ -74,7 +84,33 @@ class Scheduler(object):
self.logger.info('Starting monitor agent...')
while not self.stop:
schedule.run_pending()
time.sleep(self.configuration.data['frequency'])
time.sleep(self.configuration.endpoint['frequency'])
class NewThread(threading.Thread):
def __init__(self, scheduler):
threading.Thread.__init__(self)
self.scheduler = scheduler
def run(self):
self.scheduler.start()
def validate_config():
if 'endpoints' not in config_file.keys():
fatal_error('Endpoints is a mandatory field')
if config_file['endpoints'] is None:
fatal_error('Endpoints array can not be empty')
for key in cachet_mandatory_fields:
if key not in config_file['cachet']:
fatal_error('Missing cachet mandatory fields')
def fatal_error(message):
logging.getLogger('cachet_url_monitor.scheduler').fatal("%s", message)
sys.exit(1)
if __name__ == "__main__":
@@ -87,5 +123,13 @@ if __name__ == "__main__":
logging.getLogger('cachet_url_monitor.scheduler').fatal('Missing configuration file argument')
sys.exit(1)
scheduler = Scheduler(sys.argv[1])
scheduler.start()
try:
config_file = load(open(sys.argv[1], 'r'), SafeLoader)
except FileNotFoundError:
logging.getLogger('cachet_url_monitor.scheduler').fatal(f'File not found: {sys.argv[1]}')
sys.exit(1)
validate_config()
for endpoint_index in range(len(config_file['endpoints'])):
NewThread(Scheduler(config_file, endpoint_index)).start()