[damned-lies] Refs #265 - Clean module locks when receiving SIGTERM



commit 553d61bb7e7ba2973928ce3625ca2d9cb7e6922d
Author: Claude Paroz <claude 2xlibre net>
Date:   Sat Sep 25 11:14:44 2021 +0200

    Refs #265 - Clean module locks when receiving SIGTERM

 stats/apps.py        | 12 ++++++++++++
 stats/models.py      | 19 +++++++++++++++++--
 stats/tests/tests.py | 13 +++++++++++--
 3 files changed, 40 insertions(+), 4 deletions(-)
---
diff --git a/stats/apps.py b/stats/apps.py
new file mode 100644
index 00000000..a29a9c30
--- /dev/null
+++ b/stats/apps.py
@@ -0,0 +1,12 @@
+import signal
+
+from django.apps import AppConfig
+
+
+class StatsConfig(AppConfig):
+    name = "stats"
+
+    def ready(self):
+        from stats.models import ModuleLock
+
+        signal.signal(signal.SIGTERM, lambda *args: ModuleLock.clean_locks())
diff --git a/stats/models.py b/stats/models.py
index 1d3197fc..c92668b7 100644
--- a/stats/models.py
+++ b/stats/models.py
@@ -191,10 +191,11 @@ class ModuleLock:
     """ Weird things happen when multiple updates run in parallel for the same module
         We use filesystem directories creation/deletion to act as global lock mecanism
     """
+    dir_prefix = 'updating-'
 
     def __init__(self, mod):
         self.module = mod
-        self.dirpath = settings.LOCK_DIR / f"updating-{self.module.name}"
+        self.dirpath = settings.LOCK_DIR / f"{self.dir_prefix}{self.module.name}"
 
     def __enter__(self):
         while True:
@@ -208,14 +209,28 @@ class ModuleLock:
                 else:
                     # Something is happening on the module, let's wait.
                     sleep(10)
+        return self
 
     def __exit__(self, *exc_info):
-        self.dirpath.rmdir()
+        try:
+            self.dirpath.rmdir()
+        except OSError:
+            pass
 
     @property
     def is_locked(self):
         return self.dirpath.exists()
 
+    @classmethod
+    def clean_locks(cls):
+        # In case of urgent stops (SIGTERM, etc.)
+        for subdir in settings.LOCK_DIR.iterdir():
+            if subdir.name.startswith(cls.dir_prefix):
+                try:
+                    subdir.rmdir()
+                except OSError:
+                    continue
+
 
 @total_ordering
 class Branch(models.Model):
diff --git a/stats/tests/tests.py b/stats/tests/tests.py
index 2bff8655..8ca98ef5 100644
--- a/stats/tests/tests.py
+++ b/stats/tests/tests.py
@@ -21,8 +21,8 @@ from languages.models import Language
 from people.models import Person
 from stats import utils
 from stats.models import (
-    GLIB_PRESET, Module, Domain, Branch, Release, CategoryName, PoFile, Statistics,
-    FakeLangStatistics, Information, UnableToCommit
+    GLIB_PRESET, Branch, CategoryName, Domain, FakeLangStatistics, Information,
+    Module, ModuleLock, PoFile, Release, Statistics, UnableToCommit
 )
 from .utils import PatchShellCommand, test_scratchdir
 
@@ -60,6 +60,15 @@ class ModuleTestCase(TestCase):
         modules = [Module.objects.get(name='zenity'), Module.objects.get(name='gnome-hello')]
         self.assertEqual(sorted(modules)[0].name, 'gnome-hello')
 
+    def test_clean_module_locks(self):
+        class CustomModuleLock(ModuleLock):
+            dir_prefix = 'updating-test-'
+
+        module = Module.objects.get(name="gnome-hello")
+        with CustomModuleLock(module) as lock:
+            CustomModuleLock.clean_locks()
+            self.assertFalse(lock.dirpath.exists())
+
     def test_modules_list(self):
         response = self.client.get(reverse('modules'))
         self.assertContains(response, '<li><a href="/module/zenity/">zenity</a></li>')


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]