mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2025-04-03 00:07:05 +00:00
89 lines
2.4 KiB
Python
89 lines
2.4 KiB
Python
#####
|
|
##### This file is part of Mail-in-a-Box-LDAP which is released under the
|
|
##### terms of the GNU Affero General Public License as published by the
|
|
##### Free Software Foundation, either version 3 of the License, or (at
|
|
##### your option) any later version. See file LICENSE or go to
|
|
##### https://github.com/downtownallday/mailinabox-ldap for full license
|
|
##### details.
|
|
#####
|
|
|
|
|
|
import threading
|
|
import logging
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class Pruner(object):
|
|
'''periodically calls the prune() method of registered Prunable
|
|
objects
|
|
|
|
'''
|
|
def __init__(self, db_conn_factory, policy={
|
|
'older_than_days': 7,
|
|
'frequency_min': 60
|
|
}):
|
|
self.db_conn_factory = db_conn_factory
|
|
self.policy = policy
|
|
self.prunables = []
|
|
self.interrupt = threading.Event()
|
|
self._new_thread()
|
|
self.t.start()
|
|
|
|
|
|
def _new_thread(self):
|
|
self.interrupt.clear()
|
|
self.t = threading.Thread(
|
|
target=self._bg_pruner,
|
|
name="Pruner",
|
|
daemon=True
|
|
)
|
|
|
|
def add_prunable(self, inst):
|
|
self.prunables.append(inst)
|
|
|
|
def set_policy(self, policy):
|
|
self.stop()
|
|
self.policy = policy
|
|
# a new thread object must be created or Python(<3.8?) throws
|
|
# RuntimeError("threads can only be started once")
|
|
self._new_thread()
|
|
self.t.start()
|
|
|
|
def stop(self, do_join=True):
|
|
self.interrupt.set()
|
|
if do_join:
|
|
self.t.join()
|
|
|
|
def connect(self):
|
|
return self.db_conn_factory.connect()
|
|
|
|
def close(self, conn):
|
|
self.db_conn_factory.close(conn)
|
|
|
|
def __del__(self):
|
|
self.stop(do_join=False)
|
|
|
|
def _bg_pruner(self):
|
|
conn = self.connect()
|
|
|
|
def do_prune():
|
|
for prunable in self.prunables:
|
|
if not self.interrupt.is_set():
|
|
try:
|
|
prunable.prune(conn, self.policy)
|
|
except Exception as e:
|
|
log.exception(e)
|
|
|
|
try:
|
|
# prune right-off
|
|
do_prune()
|
|
|
|
while not self.interrupt.is_set():
|
|
# wait until interrupted or it's time to prune
|
|
if self.interrupt.wait(self.policy['frequency_min'] * 60) is not True:
|
|
do_prune()
|
|
|
|
finally:
|
|
self.close(conn)
|