python - ensure script is activated only once

2024/11/14 21:11:19

I'm writing a Python 2.7 script.
In summary, this script is being run every night on Linux and activates several processes.

I'd like to ensure this script is not run multiple times in parallel (basically trying to mimic Singleton pattern but on application level) .

Code Example

def main():# before doing anything, I'd like to know whether this# script was activated and alive. # if so, error out# do somethingif __name__ == "__main__":main()

Suggestion

The naive solution would be to create some kind of a lock file, that acts as a mutex.
The first thing we do is to check whether this file exists. if so, then other instance of the script already created it and we should error out. when the script is done, we remove this file.
I'm assuming this solution would work, as long as the operations on the file system are atomic.

Implementation

import os, syslock_file_path = ".lock_script"def lock_mutex():if os.path.exists(lock_mutex_path):print "Error: script was already activated."sys.exit(-1)else:file = open(lock_mutex_path, 'w')def unlock_mutex():assert( os.path.exists(lock_mutex_path))os.remove(lock_mutex_path)def main():try:lock_mutex()# do somethingunlock_mutex()except:unlock_mutex()if __name__ == "__main__":main()

Problem

How to ensure lock_mutex() and unlock_mutex() are atomic?

Answer

Since you're using linux, you can make use of flock:

import os
import fcntl
import timedef main():# acquire the prog lockif not prog_lock_acq('singleton.lock'):print("another instance is running")exit(1)print("program is running-press Ctrl+C to stop")while True:time.sleep(10)def prog_lock_acq(lpath):fd = Nonetry:fd = os.open(lpath, os.O_CREAT)fcntl.flock(fd, fcntl.LOCK_NB | fcntl.LOCK_EX)return Trueexcept (OSError, IOError):if fd: os.close(fd)return Falseif __name__ == '__main__':main()

It doesn't matter that we left the file open after exiting the prog_lock_acq because when the process exits, it will be automatically closed by the OS. Also, if you leave out LOCK_NB option, the flock call will block until the current running process quits. Depending on your use case, that might be useful.

Note that we're not deleting the file on exit. It doesn't matter. Existence of the file doesn't indicate a live process—the lock does. So even if you kill your process with kill -9, the lock is still released.

There is however a caveat: if you unlink the lock file while the process is running, when the next instance of the process is run, it will create a new file which will have no lock on it and will run just fine which will violate our singleton design. You might be able to do something clever with a directory to prevent unlinking but I'm not sure how robust that would be.

https://en.xdnf.cn/q/72437.html

Related Q&A

How to set up auto-deploy to AppEngine when pushing to Git Repository

Ive heard that other platforms support auto-deployment of their code to production when they push changes to their Git repository.Can I set up something similar to this for AppEngine? How?Im using Py…

#include zbar.h 1 error generated when running pip install zbar

Im trying to run pip install zbar and for some reason I cant seem to find an answer to solve this dependency issue. Any help would be extremely appreciated. See traceback below:Downloading/unpacking zb…

Django model field default based on another model field

I use Django Admin to build a management site. There are two tables, one is ModelA with data in it, another is ModelB with nothing in it. If one model field b_b in ModelB is None, it can be displayed o…

How do I improve remove duplicate algorithm?

My interview question was that I need to return the length of an array that removed duplicates but we can leave at most 2 duplicates. For example, [1, 1, 1, 2, 2, 3] the new array would be [1, 1, 2, 2,…

Looking for values in nested tuple

Say I have:t = ((dog, Dog),(cat, Cat),(fish, Fish), )And I need to check if a value is in the first bit of the nested tuple (ie. the lowercase bits). How can I do this? The capitalised values do not m…

Multiple lines user input in command-line Python application

Is there any easy way to handle multiple lines user input in command-line Python application?I was looking for an answer without any result, because I dont want to:read data from a file (I know, its t…

Performance difference between filling existing numpy array and creating a new one

In iterative algorithms, it is common to use large numpy arrays many times. Frequently the arrays need to be manually "reset" on each iteration. Is there a performance difference between fill…

Set space between boxplots in Python Graphs generated nested box plots with Seaborn?

I am trying to set a space between the boxplots (between the green and orange boxes) created with Python Seaborn modules sns.boxplot(). Please see attached the graph, that the green and orange subplot …

Geocoding using Geopy and Python

I am trying to Geocode a CSV file that contains the name of the location and a parsed out address which includes Address number, Street name, city, zip, country. I want to use GEOPY and ArcGIS Geocodes…

Making Python scripts work with xargs

What would be the process of making my Python scripts work well with xargs? For instance, I would like the following command to work through each line of text file, and execute an arbitrary command:c…