python - 在 python 脚本中检查正在运行的 python 脚本

标签 python linux unix

我正在运行一个 python 脚本,它可能需要也可能不需要几个小时才能完成。

在我的 python 脚本的开头,我想检查这个 python 脚本是否已经在运行。

如果它已经在运行,我想退出我刚刚启动的当前 python。

例如:

python 从凌晨 1 点开始,一直运行到凌晨 3 点 在凌晨 2 点开始另一个,但不知道它已经在运行。 我希望凌晨 2 点的 python 检查并退出,因为它已经在运行。

我该如何编写这个 python?


这是我尝试锁定的方法..

try:
    l = lock.lock("/home/auto.py", timeout=600) # wait at most 10 minutes

except error.LockHeld:
    e = sys.exc_info()[0]
    logging.error("Error: " + str(e) + " at main gatering Stats")
    smtpObj.sendmail(sender, receivers, message + "Error: " + str(e) + " at main gatering stats")
    exit("Fail: " + str(e) + " at main gathering Stats")
else:
    l.release()

所以我认为如果它仍在运行,将等待 10 分钟,然后退出。如果它不再运行,则运行当前的 python

最佳答案

您可以尝试使用 lockfile-create带有 r 标志的命令重试指定次数捕获 CalledProcessError 并退出,-p 标志将存储 pid 过程:

import os
import sys
from time import sleep

from subprocess import check_call, CalledProcessError

try:
    check_call(["lockfile-create", "-q","-p", "-r", "0", "-l", "my.lock"])
except CalledProcessError as e:
    print("{} is already running".format(sys.argv[0]))
    print(e.returncode)
    exit(1)


# main body

for i in range(10):
    sleep(2)
    print(1)

check_call(["rm","-f","my.lock"])

在已经运行的情况下使用上面的代码运行 test.py 脚本会输出以下内容:

$ python  lock.py 
lock.py is already running
4

选项

-q, --quiet

Suppress any output. Success or failure will only be indicated by the exit status.

-v, --verbose

Enable diagnostic output.

-l, --lock-name

Do not append .lock to the filename. This option applies to lockfile-create, lockfile-remove, lockfile-touch, or lockfile-check.

-p, --use-pid

Write the current process id (PID) to the lockfile whenever a lockfile is created, and use that pid when checking a lock's validity. See the lockfile_create(3) manpage for more information. This option applies to lockfile-create, lockfile-remove, lockfile-touch, and lockfile-check.

-o, --oneshot

Touch the lock and exit immediately. This option applies to lockfile-touch and mail-touchlock. When not provided, these commands will run forever, touching the lock once every minute until killed.

-r 重试次数, --retry 重试次数

Try to lock filename retry-count times before giving up. Each attempt will be delayed a bit longer than the last (in 5 second increments) until reaching a maximum delay of one minute between retries. If retry-count is unspecified, the default is 9 which will give up after 180 seconds (3 minutes) if all 9 lock attempts fail.

描述

The lockfile_create function creates a lockfile in an NFS safe way.

If flags is set to L_PID then lockfile_create will not only check for an existing lockfile, but it will read the contents as well to see if it contains a process id in ASCII. If so, the lockfile is only valid if that process still exists.

If the lockfile is on a shared filesystem, it might have been created by a process on a remote host. Thus the process-id checking is useless and the L_PID flag should not be set. In this case, there is no good way to see if a lockfile is stale. Therefore if the lockfile is older then 5 minutes, it will be removed. That is why the lockfile_touch function is provided: while holding the lock, it needs to be refreshed regularly (every minute or so) by calling lockfile_touch ().

The lockfile_check function checks if a valid lockfile is already present without trying to create a new lockfile.

Finally the lockfile_remove function removes the lockfile.

Algorithm

即使在 NFS 上,用于以原子方式创建锁定文件的算法如下:

1

A unique file is created. In printf format, the name of the file is .lk%05d%x%s. The first argument (%05d) is the current process id. The second argument (%x) consists of the 4 minor bits of the value returned by time(2). The last argument is the system hostname.

2

Then the lockfile is created using link(2). The return value of link is ignored.

3

Now the lockfile is stat()ed. If the stat fails, we go to step 6.

4

The stat value of the lockfile is compared with that of the temporary file. If they are the same, we have the lock. The temporary file is deleted and a value of 0 (success) is returned to the caller.

5

A check is made to see if the existing lockfile is a valid one. If it isn't valid, the stale lockfile is deleted.

6

Before retrying, we sleep for n seconds. n is initially 5 seconds, but after every retry 5 extra seconds is added up to a maximum of 60 seconds (an incremental backoff). Then we go to step 2 up to retries times.

似乎有一个等效的包叫做 lockfile-progsredhat 上。

在 Mac 上你可以使用 lockfile并做类似的事情:

import os
import sys
from time import sleep
import os
from subprocess import Popen, CalledProcessError, check_call


p = Popen(["lockfile", "-r", "0", "my.lock"])
p.wait()
if p.returncode == 0:
    with open("my.pid", "w") as f:
        f.write(str(os.getpid()))
else:
    try:
        with open("my.pid") as f:
            # see if process is still running or lockfile
            # is left over from previous run.
            r = f.read()
            check_call(["kill", "-0", "{}".format(r)])
    except CalledProcessError:
        # remove old lock file and create new
        check_call(["rm", "-f", "my.lock"])
        check_call(["lockfile", "-r", "0", "my.lock"])
        # update pid
        with open("my.pid", "w") as out:
            out.write(str(os.getpid()))
        print("Deleted stale lockfile.")
    else:
        print("{} is already running".format(sys.argv[0]))
        print(p.returncode)
        exit(1)
# main body

for i in range(10):
    sleep(1)
    print(1)
check_call(["rm", "-f", "my.lock"])

在您的情况下,也许可以使用套接字:

from socket import socket, gethostname, error, SO_REUSEADDR, SOL_SOCKET
from sys import argv
import  errno



sock = socket()

# Create a socket object
host = gethostname()  
# /proc/sys/net/ipv4/ip_local_port_range is  32768  61000 on my Ubuntu Machine
port = 60001  
# allow connection in TIME_WAIT
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

try:
    sock.bind((host, port))
    sock.connect((host, port))
except error as e:
    # [Errno 99] Cannot assign requested address
    if e.errno == errno.EADDRNOTAVAIL:
        print("{} is already running".format(argv[0]))
        exit(1)
    # else raise the error
    else:
        raise e

# main body
from time import sleep

while True:
    print(1)
    sleep(2)

sock.close()

关于python - 在 python 脚本中检查正在运行的 python 脚本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29520587/

相关文章:

linux - mac上的常用命令行

c - fork 和现有线程?

linux - 如何在单个命令行中终止(如果进程退出)并重新启动进程

python - PyGTK:移动自定义构建工具提示窗口

python : Dot product of dask array

python - 如何在 Python 中创建包保护的构造函数?

python - 按 shell/python 中的某个字段对文本文件进行排序

regex - 为什么 POSIX "printable characters"类不匹配简单字符串?

python - reshape Pandas 数据框将一行反转为多列

linux - 目录过滤