nginx-amplify-agent/amplify/ext/abstract/runner.py

112 lines
3.1 KiB
Python

# -*- coding: utf-8 -*-
import abc
import time
from threading import current_thread
from amplify.agent.common.context import context
__author__ = "Grant Hulegaard"
__copyright__ = "Copyright (C) Nginx, Inc. All rights reserved."
__license__ = ""
__maintainer__ = "Grant Hulegaard"
__email__ = "grant.hulegaard@nginx.com"
class AbstractExtRunner(object):
"""
A runner is an encapsulated body that is spawned by a manager that should
have a single lifecycle. This differs from a Manager which is meant to
indefenitely run in a loop until externaly stopped.
"""
__slots__ = ('running', 'in_container')
name = 'abstact_ext_runner'
def __init__(self):
self.running = False
self.in_container = bool(context.app_config['credentials']['imagename'])
@property
def status(self):
return 'running' if self.running else 'stopped'
def _setup(self):
"""
Special method that is run before self._run(). May be used by
child objects to do work before main logic.
Exceptions in this logic will prevent main logic from running.
"""
pass
@abc.abstractmethod
def _run(self):
# Example since this is an abstract method.
try:
pass # Do something here...
except:
context.default_log.error('failed', exc_info=True)
raise
def _teardown(self):
"""
Special method that is run after self._run(). May be used by
child objects to do work after main logic.
This logic is guaranteed to run even if main logic fails.
Exceptions in this logic are unhandled by the runner.
"""
pass
def start(self):
"""
Execution entry point. Does some setup and then runs the _run routine.
"""
# TODO: Standardize this with collectors and managers.
current_thread().name = self.name
context.setup_thread_id()
self.running = True
context.inc_action_id()
start = time.time()
try:
self._setup()
self._run()
except Exception as e:
context.default_log.error(
'"%s" critical exception "%s" caught during run' % (
self.__class__.__name__,
e.__class__.__name__
)
)
context.default_log.debug('additional info:', exc_info=True)
finally:
try:
self._teardown()
finally:
end = time.time()
context.default_log.debug(
'%s (%s) run complete in %0.2f' % (
self.__class__.__name__,
id(self),
end - start
)
)
self.stop()
def stop(self):
self.running = False
context.teardown_thread_id()
def __del__(self):
"""
This is meant to catch situations where GC cleans up a routine that
found itself in an invalid state.
"""
if self.running:
self.stop()