封装了一下文件锁,方便使用。
在flask中,经常使用Flask-APScheduler进行任务调度。如果使用gunicorn来管理flask,可以启动多个flask进程。
例如:
nohup gunicorn -w 4 -b 0.0.0.0:5000 myflask:app &
根据-w 4的值,可以启动4个flask进程,每个进程拥有一个独立的内存空间,管理自己的 Flask-APScheduler;当Flask-APScheduler启动新的任务时,必然会重复启动4个相同的任务。
在同一时间内,如果希望相同内容的任务只有一个,那么,可以采用全局可见的文件锁。只有一个任务可以申请到锁,其他3个任务申请锁失败,使其自动退出,这样就保证任务的唯一性了。
python释放对象的时间,没有C++那么可控。所以,本类设计中,需要手动进行lock、unlock。即进入任务lock,执行完任务时unlock。
# coding=utf-8
'''
文件锁
'''
import atexit
import platform
import atexit
from flask_apscheduler import APScheduler
#动态载入模块
fcntl = None
msvcrt = None
bLinux = True
if platform.system() != 'Windows':
fcntl = __import__("fcntl")
bLinux = True
else:
msvcrt = __import__('msvcrt')
bLinux = False
#文件锁
class CFileLock:
def __init__(self, filename):
self.filename = filename + '.lock'
self.file = None
#文件锁
def lock(self):
if bLinux is True:
self.file = open(self.filename, 'wb')
try:
fcntl.flock(self.file, fcntl.LOCK_EX | fcntl.LOCK_NB)
print(self.filename, ' file_lock success ********')
except:
print(self.filename, ' file_lock error')
return False
else:
self.file = open(self.filename, 'wb')
try:
msvcrt.locking(self.file.fileno(), msvcrt.LK_NBLCK, 1)
print(self.filename, ' file_lock success ********')
except:
print(self.filename, ' file_lock error')
return False
return True
def unlock(self):
try:
if bLinux is True:
fcntl.flock(self.file, fcntl.LOCK_UN)
self.file.close()
else:
self.file.seek(0)
msvcrt.locking(self.file.fileno(), msvcrt.LK_UNLCK, 1)
print(self.filename, ' file_unlock success')
except:
print('file_unlock error')
用法:
# 任务调度,DB保活
def aps_keep_db_alive(self):
my_lock = filelock.CFileLock(sys._getframe().f_code.co_name)
if my_lock.lock() is False:
print(tools.get_cur_time(), ' out CSchedulerMgr ... aps_keep_db_alive, lock failed')
return
#do something
my_lock.unlock()