We often face an issue that our long running services need some parts to be reloadable without restart of such service. To achieve this I implemented simple abstract class that wraps any container we could use. You can find whole example at my Github page.
from abc import ABC, abstractmethod import time class Reloadable(ABC): """ This class wraps a container and expose all its methods. It reloads its content after `reload_every_secs` from `path`. """ def __init__(self, path, reload_every_secs=60): self._path = path self._last_update = time.time() self._reload_every_secs = reload_every_secs self._initialize_data() self.reload() def reload(self): self._last_update = time.time() try: with open(self._path) as f: self._fill_data(f) except FileNotFoundError: self._initialize_data() @abstractmethod def _initialize_data(self): """Change container to initial state""" pass @abstractmethod def _fill_data(self, fp): """Fill data from file to container self._data""" pass def access(self): if time.time() - self._last_update > self._reload_every_secs: self.reload() def __getattr__(self, item): return getattr(self._data, item) def __len__(self): self.access() return self._data.__len__() def __getitem__(self, item): self.access() return self._data.__getitem__(item) def __setitem__(self, key, value): self.access() return self._data.__setitem__(key, value) def __delitem__(self, key): self.access() return self._data.__delitem__(key) def __iter__(self): self.access() return self._data.__iter__() def __reversed__(self): self.access() return self._data.__reversed__() def __contains__(self, item): self.access() return self._data.__contains__(item) def __str__(self): self.access() return self._data.__str__() As you can see this class just wraps not specified container and whenever we want to interact with it somehow we trigger function access(). To actually use it simply implement two methods _initialize_data and _fill_data and you will have your container reloaded every few second as you can specify.
...