Make sure lockfile always sets locktime. Use locktime in cron.py to
authorScott Gasch <[email protected]>
Wed, 19 Oct 2022 21:23:39 +0000 (14:23 -0700)
committerScott Gasch <[email protected]>
Wed, 19 Oct 2022 21:23:39 +0000 (14:23 -0700)
optionally create a record of lockfile contention for future analysis.

examples/cron/cron.py
src/pyutils/files/lockfile.py

index 2a067703c9c032ab46fb3dcf72e5770de44ca044..958aa619309a4d9109939d09bf4e7d6b190fc986 100755 (executable)
@@ -26,6 +26,12 @@ cfg.add_argument(
     metavar='LOCKFILE_PATH',
     help='Path to the lockfile to use to ensure that two instances of a command do not execute contemporaneously.',
 )
+cfg.add_argument(
+    '--lockfile_audit_record',
+    default=None,
+    metavar='LOCKFILE_AUDIT_RECORD_FILENAME',
+    help='Path to a record of when the logfile was held/released and for what reason',
+)
 cfg.add_argument(
     '--timeout',
     type=str,
@@ -147,8 +153,22 @@ def main() -> int:
                 do_signal_cleanup=True,
                 override_command=' '.join(config.config['command']),
                 expiration_timestamp=lockfile_expiration,
-            ):
-                return run_command(timeout, timestamp_file)
+            ) as lf:
+                record = config.config['lockfile_audit_record']
+                cmd = ' '.join(config.config['command'])
+                if record:
+                    with open(record, 'a') as wf:
+                        print(
+                            f'{lockfile_path}, ACQUIRE, {lf.locktime}, {cmd}', file=wf
+                        )
+                retval = run_command(timeout, timestamp_file)
+                if record:
+                    with open(record, 'a') as wf:
+                        print(
+                            f'{lockfile_path}, RELEASE, {datetime.datetime.now().timestamp()}, {cmd}',
+                            file=wf,
+                        )
+                return retval
         except lockfile.LockFileException as e:
             logger.exception(e)
             msg = f'Failed to acquire {lockfile_path}, giving up.'
index 0febca6bf5b754682f5e91f8604c70e566fd8a0d..c7b4841e5373779d6c0bc783f7ce6f32270c9273 100644 (file)
@@ -91,7 +91,7 @@ class LockFile(contextlib.AbstractContextManager):
         """
         self.is_locked: bool = False
         self.lockfile: str = lockfile_path
-        self.locktime: Optional[int] = None
+        self.locktime: Optional[float] = None
         self.override_command: Optional[str] = override_command
         if do_signal_cleanup:
             signal.signal(signal.SIGINT, self._signal)
@@ -122,6 +122,7 @@ class LockFile(contextlib.AbstractContextManager):
                 contents = self._get_lockfile_contents()
                 logger.debug(contents)
                 f.write(contents)
+            self.locktime = datetime.datetime.now().timestamp()
             logger.debug('Success; I own %s.', self.lockfile)
             self.is_locked = True
             return True
@@ -174,7 +175,6 @@ class LockFile(contextlib.AbstractContextManager):
 
     def __enter__(self):
         if self.acquire_with_retries():
-            self.locktime = datetime.datetime.now().timestamp()
             return self
         msg = f"Couldn't acquire {self.lockfile}; giving up."
         logger.warning(msg)