This will be more of a theoretical question. I have implemented a cache for my "special" needs. This cache holds handles to subprocesses that would run indefinitely if not stopped through a message sent to them through unix named pipes. My cache uses an active time based eviction policy using a single background daemon thread.
Now the problem comes up when the main program terminates and the cache still has entries. I thought I'd use atexit on a staticmethod within my Cache class, but by the time atexit invokes my cleanup function the entries are freed making me unable to shut down the associated subprocess.
class LinkedList(object):
# Standard doubly linked-list implementation with a twist: get(Node) will make the retrieved node the header.
pass
zero = Node(0)
one = Node(1)
two = Node(2)
l = LinkedList()
l.prepend(zero)
l.prepend(one)
l.prepend(two)
l.print() # Prints the list from tail to head
0
1
2
l.get(one)
l.print()
0
2
1
My cache is a class based decorator but I'd rather not go into too much detail:
class Cache(object):
list = LinkedList()
def borrow(*args, **kwargs):
# check capacity, evict tail if necessary is omitted
list.prepend(node)
return node
@staticmethod
def cleanup():
Cache.list.print()
atexit.register(Cache.cleanup)
In the logs I see the following with a capacity of 3:
Caching: 0
Cached(0): 0
Caching: 1
Cached(1): 1, 0
Caching: 2
Cached(2): 2, 1, 0
Caching: 3
Evicting(0): 3, 2, 1
Cached(3): 3, 2, 1
Caching(4):
Evicting(1): 4, 3, 2
Cached(4): 4, 3, 2
Cleanup:
During cleanup my list becomes empty, my nodes are gone. Seems like during exit the atexit handler runs after the objects that I need are already freed up and my handles for the subprocesses are gone, meaning I have no way of terminating them. Is there something similar to atexit.register that runs on exit while I still have my objects?
@Update: As per my main application is flask:
app = flask.Flask(__name__)
try:
# read configuration
# configure loggers
app.run(host=util.get_hostname(), port=config.get_port(), debug=config.is_debug, processes=1, threaded=True)
except:
# handle exceptions
The rest is the same as originally provided. One special note is that within my environment hosts are restarted automatically each Monday. Every running application gets a SIGTERM, then given ~2minutes to shut down before getting a SIGKILL.