##// END OF EJS Templates
added latest changes
added latest changes

File last commit:

r5608:6d33e504 default
r5658:a109f5ac merge default
Show More
pidlock.py
144 lines | 4.6 KiB | text/x-python | PythonLexer
core: updated copyright to 2024
r5608 # Copyright (C) 2010-2024 RhodeCode GmbH
project: added all source files and assets
r1 #
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import os
import errno
from multiprocessing.util import Finalize
class LockHeld(Exception):
pass
class DaemonLock(object):
"""daemon locking
USAGE:
try:
l = DaemonLock(file_='/path/tolockfile',desc='test lock')
main()
l.release()
except LockHeld:
sys.exit(1)
"""
def __init__(self, file_=None, callbackfn=None,
desc='daemon lock', debug=False):
lock_name = os.path.join(os.path.dirname(__file__), 'running.lock')
self.pidfile = file_ if file_ else lock_name
self.callbackfn = callbackfn
self.desc = desc
self.debug = debug
self.held = False
pidlock: use fstring where aplicable
r5021 # run the lock automatically !
project: added all source files and assets
r1 self.lock()
self._finalize = Finalize(self, DaemonLock._on_finalize,
args=(self, debug), exitpriority=10)
@staticmethod
def _on_finalize(lock, debug):
if lock.held:
if debug:
pidlock: use fstring where aplicable
r5021 print('lock held finalazing and running lock.release()')
project: added all source files and assets
r1 lock.release()
def lock(self):
"""
locking function, if lock is present it
will raise LockHeld exception
"""
pidlock: use fstring where aplicable
r5021 lockname = f'{os.getpid()}'
project: added all source files and assets
r1 if self.debug:
core: use py3 compatible prints
r3057 print('running lock')
project: added all source files and assets
r1 self.trylock()
self.makelock(lockname, self.pidfile)
return True
def trylock(self):
running_pid = False
if self.debug:
core: use py3 compatible prints
r3057 print('checking for already running process')
project: added all source files and assets
r1 try:
with open(self.pidfile, 'r') as f:
try:
running_pid = int(f.readline())
except ValueError:
running_pid = -1
if self.debug:
pidlock: use fstring where aplicable
r5021 print(f'lock file present running_pid: {running_pid}, '
f'checking for execution')
project: added all source files and assets
r1 # Now we check the PID from lock file matches to the current
# process PID
if running_pid:
try:
python3: removed compat modules
r4928 os.kill(running_pid, 0)
project: added all source files and assets
r1 except OSError as exc:
if exc.errno in (errno.ESRCH, errno.EPERM):
pidlock: use fstring where aplicable
r5021 print("Lock File is there but the program is not running")
print(f"Removing lock file for the: {running_pid}")
project: added all source files and assets
r1 self.release()
else:
raise
else:
core: use py3 compatible prints
r3057 print("You already have an instance of the program running")
pidlock: use fstring where aplicable
r5021 print(f"It is running as process {running_pid}")
project: added all source files and assets
r1 raise LockHeld()
except IOError as e:
if e.errno != 2:
raise
def release(self):
"""releases the pid by removing the pidfile
"""
if self.debug:
core: use py3 compatible prints
r3057 print('trying to release the pidlock')
project: added all source files and assets
r1
if self.callbackfn:
core: use py3 compatible prints
r3057 # execute callback function on release
project: added all source files and assets
r1 if self.debug:
pidlock: use fstring where aplicable
r5021 print(f'executing callback function {self.callbackfn}')
project: added all source files and assets
r1 self.callbackfn()
try:
if self.debug:
pidlock: use fstring where aplicable
r5021 print(f'removing pidfile {self.pidfile}')
project: added all source files and assets
r1 os.remove(self.pidfile)
self.held = False
except OSError as e:
if self.debug:
pidlock: use fstring where aplicable
r5021 print(f'removing pidfile failed {e}')
project: added all source files and assets
r1 pass
def makelock(self, lockname, pidfile):
"""
this function will make an actual lock
:param lockname: acctual pid of file
:param pidfile: the file to write the pid in
"""
if self.debug:
pidlock: use fstring where aplicable
r5021 print(f'creating a file {lockname} and pid: {pidfile}')
project: added all source files and assets
r1
dir_, file_ = os.path.split(pidfile)
if not os.path.isdir(dir_):
os.makedirs(dir_)
with open(self.pidfile, 'wb') as f:
f.write(lockname)
self.held = True