#!/usr/bin/env python3
-from dataclasses import dataclass
import datetime
import json
import logging
import os
import signal
import sys
-from typing import Optional
import warnings
+from dataclasses import dataclass
+from typing import Optional
import config
import datetime_utils
import decorator_utils
-
-cfg = config.add_commandline_args(
- f'Lockfile ({__file__})',
- 'Args related to lockfiles')
+cfg = config.add_commandline_args(f'Lockfile ({__file__})', 'Args related to lockfiles')
cfg.add_argument(
'--lockfile_held_duration_warning_threshold_sec',
type=float,
- default=10.0,
+ default=60.0,
metavar='SECONDS',
- help='If a lock is held for longer than this threshold we log a warning'
+ help='If a lock is held for longer than this threshold we log a warning',
)
logger = logging.getLogger(__name__)
class LockFileContents:
pid: int
commandline: str
- expiration_timestamp: float
+ expiration_timestamp: Optional[float]
class LockFile(object):
# some logic for detecting stale locks.
"""
+
def __init__(
- self,
- lockfile_path: str,
- *,
- do_signal_cleanup: bool = True,
- expiration_timestamp: Optional[float] = None,
- override_command: Optional[str] = None,
+ self,
+ lockfile_path: str,
+ *,
+ do_signal_cleanup: bool = True,
+ expiration_timestamp: Optional[float] = None,
+ override_command: Optional[str] = None,
) -> None:
self.is_locked = False
self.lockfile = lockfile_path
pass
msg = f'Could not acquire {self.lockfile}.'
logger.warning(msg)
- warnings.warn(msg)
return False
def acquire_with_retries(
- self,
- *,
- initial_delay: float = 1.0,
- backoff_factor: float = 2.0,
- max_attempts = 5
+ self,
+ *,
+ initial_delay: float = 1.0,
+ backoff_factor: float = 2.0,
+ max_attempts=5,
) -> bool:
-
- @decorator_utils.retry_if_false(tries = max_attempts,
- delay_sec = initial_delay,
- backoff = backoff_factor)
+ @decorator_utils.retry_if_false(
+ tries=max_attempts, delay_sec=initial_delay, backoff=backoff_factor
+ )
def _try_acquire_lock_with_retries() -> bool:
success = self.try_acquire_lock_once()
if not success and os.path.exists(self.lockfile):
return self
msg = f"Couldn't acquire {self.lockfile}; giving up."
logger.warning(msg)
- warnings.warn(msg)
raise LockFileException(msg)
def __exit__(self, type, value, traceback):
cmd = self.override_command
else:
cmd = ' '.join(sys.argv)
- print(cmd)
contents = LockFileContents(
- pid = os.getpid(),
- commandline = cmd,
- expiration_timestamp = self.expiration_timestamp,
+ pid=os.getpid(),
+ commandline=cmd,
+ expiration_timestamp=self.expiration_timestamp,
)
return json.dumps(contents.__dict__)
except OSError:
msg = f'Lockfile {self.lockfile}\'s pid ({contents.pid}) is stale; force acquiring'
logger.warning(msg)
- warnings.warn(msg)
self.release()
# Has the lock expiration expired?
if contents.expiration_timestamp is not None:
now = datetime.datetime.now().timestamp()
- if now > contents.expiration_datetime:
+ if now > contents.expiration_timestamp:
msg = f'Lockfile {self.lockfile} expiration time has passed; force acquiring'
logger.warning(msg)
- warnings.warn(msg)
self.release()
except Exception:
pass