Okay, this was a bit more complex, and a bit simpler than I thought.
1) The Django app __init__ is the only place you can place the signal to stop the watchdog function.
2) You can’t perform any app model specific work in the __init__ because the app’s model frame work wasn’t yet finished initializing. So I ended up with a chicken & egg situation.
Now, this does *exactly* what I needed to do, so this might not be needed for anyone else, but it without a doubt simplifies any sort of file caching issue, since you can invalidate the cache with whatever granularity you wanted (eg File Level, or in my case, Directory level).
I created a class to contain the watchdog specific code, and a table that stored the list of cached directories (to invalidate, I just remove the directory name from that table).
The existing scanning code is just bypassed if it’s already been scanned, if it’s invalidated, it’ll just refresh the listing(s) in the database.
eg.
in watchdogmon.py:
class watchdog_monitor():
def __init__(self):
self.my_observer = Observer()
self.my_event_handler = None
def on_event(self, event):
pass
def startup(self, monitor_path, created=None,
deleted=None, modified=None,
moved=None):
print("Monitoring :", monitor_path)
case_sensitive = False
self.my_event_handler = PatternMatchingEventHandler(patterns, ignore_patterns,
ignore_directories,
case_sensitive)
self.my_event_handler.on_created = created
self.my_event_handler.on_deleted = deleted
self.my_event_handler.on_modified = modified
self.my_event_handler.on_moved = moved
go_recursively = True
self.my_observer = Observer()
self.my_observer.schedule(self.my_event_handler,
monitor_path,
recursive=go_recursively)
self.my_observer.start()
def shutdown(self, *args):
if os.environ.get('RUN_MAIN') == 'true':
print("Shutting down")
self.my_observer.stop()
self.my_observer.join()
# signal.send('system')
sys.exit(0) # So runserver does try to exit
watchdog = watchdog_monitor()
In __init__.py:
signal.signal(signal.SIGINT, watchdogmon.watchdog.shutdown)
In views.py:
print("Clearing all entries from Cache Tracking")
Cache_Tracking.objects.all().delete()
print("Starting Watchdog")
from frontend.utilities import delete_from_cache_tracking
watchdog.startup(monitor_path=os.path.join(configdata["locations"]["albums_path"],
"albums"), created=delete_from_cache_tracking,
deleted=delete_from_cache_tracking,
modified=delete_from_cache_tracking,
moved=delete_from_cache_tracking)
where delete_from_cache_tracking, just deletes the event.src_path from the cache_Tracking table.
Now, the drawback here is that watchdog utilizes the fsevents framework under Mac OS X, so there is no practical limit to what it can track, the OS is doing the work watchdog is wrapping around OS provided functionality. (Or at least that is my understanding)
So under Mac OS X, it’s tracking probably millions or at least 10’s of thousands of files, and directories.
Under Windows, or Unix, my understanding is that watchdog requires a file handle per directory? So some tweaking maybe required to prevent from running out of file handles under a large directory structure / number of files.
Hope this helps someone else that is trying to integrate watchdog into Django.
- BEnjamin