GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — kale/action-datastore (#6)
by Manas
05:59
created

st2reactor.garbage_collector.GarbageCollectorService   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 130
Duplicated Lines 0 %
Metric Value
wmc 25
dl 0
loc 130
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A _main_loop() 0 7 2
A __init__() 0 13 1
A shutdown() 0 2 1
A handle_sigusr2() 0 3 1
B _validate_ttl_values() 0 9 5
B _purge_trigger_instances() 0 24 4
A _perform_garbage_collection() 0 16 3
A _register_signal_handlers() 0 2 1
A run() 0 18 3
B _purge_action_executions() 0 25 4
1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
"""
17
Garbage collection service which deletes old data from the database.
18
"""
19
20
import signal
21
import datetime
22
23
import eventlet
24
from eventlet.support import greenlets as greenlet
25
from oslo_config import cfg
26
27
from st2common import log as logging
28
from st2common.constants.exit_codes import SUCCESS_EXIT_CODE
29
from st2common.constants.exit_codes import FAILURE_EXIT_CODE
30
from st2common.constants.garbage_collection import DEFAULT_COLLECTION_INTERVAL
31
from st2common.constants.garbage_collection import MINIMUM_TTL_DAYS
32
from st2common.util import isotime
33
from st2common.util.date import get_datetime_utc_now
34
from st2common.garbage_collection.executions import purge_executions
35
from st2common.garbage_collection.trigger_instances import purge_trigger_instances
36
37
__all__ = [
38
    'GarbageCollectorService'
39
]
40
41
LOG = logging.getLogger(__name__)
42
43
44
class GarbageCollectorService(object):
45
    def __init__(self, collection_interval=DEFAULT_COLLECTION_INTERVAL):
46
        """
47
        :param collection_interval: How often to check database for old data and perform garbage
48
               collection.
49
        :type collection_interval: ``int``
50
        """
51
        self._collection_interval = collection_interval
52
53
        self._action_executions_ttl = cfg.CONF.garbagecollector.action_executions_ttl
54
        self._trigger_instances_ttl = cfg.CONF.garbagecollector.trigger_instances_ttl
55
        self._validate_ttl_values()
56
57
        self._running = True
58
59
    def run(self):
60
        self._register_signal_handlers()
61
62
        # Wait a couple of seconds before performing initial collection to prevent thundering herd
63
        # effect when restarting multiple services at the same time
64
        eventlet.sleep(2)
65
66
        try:
67
            self._main_loop()
68
        except greenlet.GreenletExit:
69
            self._running = False
70
            return SUCCESS_EXIT_CODE
71
        except Exception as e:
72
            LOG.exception('Exception in the garbage collector: %s' % (str(e)))
73
            self._running = False
74
            return FAILURE_EXIT_CODE
75
76
        return SUCCESS_EXIT_CODE
77
78
    def _register_signal_handlers(self):
79
        signal.signal(signal.SIGUSR2, self.handle_sigusr2)
80
81
    def handle_sigusr2(self, signal_number, stack_frame):
82
        LOG.info('Forcing garbage collection...')
83
        self._perform_garbage_collection()
84
85
    def shutdown(self):
86
        self._running = False
87
88
    def _main_loop(self):
89
        while self._running:
90
            self._perform_garbage_collection()
91
92
            LOG.info('Sleeping for %s seconds before next garbage collection...' %
93
                     (self._collection_interval))
94
            eventlet.sleep(self._collection_interval)
95
96
    def _validate_ttl_values(self):
97
        """
98
        Validate that a user has supplied reasonable TTL values.
99
        """
100
        if self._action_executions_ttl and self._action_executions_ttl < MINIMUM_TTL_DAYS:
101
            raise ValueError('Minimum possible TTL in days is %s' % (MINIMUM_TTL_DAYS))
102
103
        if self._trigger_instances_ttl and self._trigger_instances_ttl < MINIMUM_TTL_DAYS:
104
            raise ValueError('Minimum possible TTL in days is %s' % (MINIMUM_TTL_DAYS))
105
106
    def _perform_garbage_collection(self):
107
        LOG.info('Performing garbage collection...')
108
109
        # todo sleep between queries to avoid busy waiting
110
        if self._action_executions_ttl >= MINIMUM_TTL_DAYS:
111
            self._purge_action_executions()
112
        else:
113
            LOG.debug('Skipping garbage collection for action executions since it\'s not '
114
                      'configured')
115
116
        # Note: We sleep for a bit between garbage collection of each object
117
        # type to prevent busy waiting
118
        if self._trigger_instances_ttl >= MINIMUM_TTL_DAYS:
119
            self._purge_trigger_instances()
120
        else:
121
            LOG.debug('Skipping garbage collection for trigger instances since it\'s not '
122
                      'configured')
123
124
    def _purge_action_executions(self):
125
        """
126
        Purge action executions and corresponding live actions which match the criteria defined in
127
        the config.
128
        """
129
        LOG.info('Performing garbage collection for action executions')
130
131
        utc_now = get_datetime_utc_now()
132
        timestamp = (utc_now - datetime.timedelta(days=self._action_executions_ttl))
133
134
        # Another sanity check to make sure we don't delete new executions
135
        if timestamp > (utc_now - datetime.timedelta(days=MINIMUM_TTL_DAYS)):
136
            raise ValueError('Calculated timestamp would violate the minimum TTL constraint')
137
138
        timestamp_str = isotime.format(dt=timestamp)
139
        LOG.info('Deleting action executions older than: %s' % (timestamp_str))
140
141
        assert timestamp < utc_now
142
143
        try:
144
            purge_executions(logger=LOG, timestamp=timestamp)
145
        except Exception as e:
146
            LOG.exception('Failed to delete executions: %s' % (str(e)))
147
148
        return True
149
150
    def _purge_trigger_instances(self):
151
        """
152
        Purge trigger instances which match the criteria defined in the config.
153
        """
154
        LOG.info('Performing garbage collection for trigger instances')
155
156
        utc_now = get_datetime_utc_now()
157
        timestamp = (utc_now - datetime.timedelta(days=self._trigger_instances_ttl))
158
159
        # Another sanity check to make sure we don't delete new executions
160
        if timestamp > (utc_now - datetime.timedelta(days=MINIMUM_TTL_DAYS)):
161
            raise ValueError('Calculated timestamp would violate the minimum TTL constraint')
162
163
        timestamp_str = isotime.format(dt=timestamp)
164
        LOG.info('Deleting trigger instances older than: %s' % (timestamp_str))
165
166
        assert timestamp < utc_now
167
168
        try:
169
            purge_trigger_instances(logger=LOG, timestamp=timestamp)
170
        except Exception as e:
171
            LOG.exception('Failed to trigger instances: %s' % (str(e)))
172
173
        return True
174