简体   繁体   English

检查python脚本中运行的python脚本

[英]Checking running python script within the python script

I am running a python script that may or may not take few hours to complete. 我正在运行一个python脚本,可能需要或可能不需要几个小时才能完成。

In the beginning of my python script, I want to check if this python script is already running or not. 在我的python脚本的开头,我想检查这个python脚本是否已经运行。

If it is already running, I want to exit my current python that I just started. 如果它已经运行,我想退出我刚刚开始的当前python。

For example: 例如:

python started 1AM and keeps on running until 3AM started another one at 2AM without knowing it is already running. python在凌晨1点开始运行,并一直运行到凌晨3点,在凌晨2点开始另一个,而不知道它已经在运行。 I want my 2AM python to check and exit since it is already running. 我希望我的2AM python检查并退出,因为它已经在运行。

How can I write this python? 我该怎么写这个python?


This is what I tried for locking.. 这是我试图锁定..

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()

so I thought this will wait for 10 minutes if it is still running then exit.. if it is not running anymore, then run the current python 所以我认为这将等待10分钟,如果它仍在运行然后退出..如果它不再运行,然后运行当前的python

You can try using the lockfile-create command with the r flag to retry a specified amount of times catching a CalledProcessError and exiting, the -p flag will store the pid of the process : 您可以尝试使用带有r标志的CalledProcessError -create命令重试指定的次数来捕获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"])

Running a test.py script with the code above while one is already running outputs the following: 运行带有上述代码的test.py脚本,而其中一个已在运行时输出以下内容:

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

Options 选项

-q, --quiet -q, - quiet

Suppress any output. 抑制任何输出。 Success or failure will only be indicated by the exit status. 成功或失败仅由退出状态指示。

-v, --verbose -v, - verbose

Enable diagnostic output. 启用诊断输出。

-l, --lock-name -l, - lock-name

Do not append .lock to the filename. 不要将.lock附加到文件名。 This option applies to lockfile-create, lockfile-remove, lockfile-touch, or lockfile-check. 此选项适用于lockfile-create,lockfile-remove,lockfile-touch或lockfile-check。

-p, --use-pid -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. 无论何时创建锁文件,都将当前进程ID(PID)写入锁文件,并在检查锁的有效性时使用该pid。 See the lockfile_create(3) manpage for more information. 有关更多信息,请参见lockfile_create(3)联机帮助页。 This option applies to lockfile-create, lockfile-remove, lockfile-touch, and lockfile-check. 此选项适用于lockfile-create,lockfile-remove,lockfile-touch和lockfile-check。

-o, --oneshot -o, - oneshot

Touch the lock and exit immediately. 触摸锁定并立即退出。 This option applies to lockfile-touch and mail-touchlock. 此选项适用于lockfile-touch和mail-touchlock。 When not provided, these commands will run forever, touching the lock once every minute until killed. 如果没有提供,这些命令将永远运行,每分钟触摸一次锁直到被杀死。

-r retry-count, --retry retry-count -r retry-count, - retry-retry-count

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. 每次尝试都会比最后一次尝试延迟一点(以5秒为增量),直到重试之间达到最大延迟一分钟。 If retry-count is unspecified, the default is 9 which will give up after 180 seconds (3 minutes) if all 9 lock attempts fail. 如果未指定retry-count,则默认值为9,如果所有9次锁定尝试都失败,则会在180秒(3分钟)后放弃。

Description 描述

The lockfile_create function creates a lockfile in an NFS safe way. lockfile_create函数以NFS安全方式创建锁文件。

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. 如果flags设置为L_PID,则lockfile_create不仅会检查现有的锁文件,还会读取内容以查看它是否包含ASCII中的进程ID。 If so, the lockfile is only valid if that process still exists. 如果是,则lockfile仅在该进程仍然存在时有效。

If the lockfile is on a shared filesystem, it might have been created by a process on a remote host. 如果lockfile位于共享文件系统上,则它可能是由远程主机上的进程创建的。 Thus the process-id checking is useless and the L_PID flag should not be set. 因此,进程ID检查是无用的,不应设置L_PID标志。 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. 因此,如果锁定文件超过5分钟,它将被删除。 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 (). 这就是提供lockfile_touch函数的原因:在持有锁时,需要通过调用lockfile_touch()定期刷新(每分钟左右)。

The lockfile_check function checks if a valid lockfile is already present without trying to create a new lockfile. lockfile_check函数检查是否已存在有效的锁文件,而不尝试创建新的锁文件。

Finally the lockfile_remove function removes the lockfile. 最后,lockfile_remove函数删除了lockfile。

The Algorithm 算法

The algorithm that is used to create a lockfile in an atomic way, even over NFS, is as follows: 用于以原子方式创建锁文件的算法,甚至是通过NFS,如下所示:

1 1

A unique file is created. 将创建一个唯一文件。 In printf format, the name of the file is .lk%05d%x%s. 在printf格式中,文件名是.lk%05d%x%s。 The first argument (%05d) is the current process id. 第一个参数(%05d)是当前进程ID。 The second argument (%x) consists of the 4 minor bits of the value returned by time(2). 第二个参数(%x)由time(2)返回的值的4个次要位组成。 The last argument is the system hostname. 最后一个参数是系统主机名。

2 2

Then the lockfile is created using link(2). 然后使用link(2)创建lockfile。 The return value of link is ignored. 链接的返回值被忽略。

3 3

Now the lockfile is stat()ed. 现在lockfile是stat()ed。 If the stat fails, we go to step 6. 如果统计失败,我们转到步骤6。

4 4

The stat value of the lockfile is compared with that of the temporary file. 将lockfile的stat值与临时文件的stat值进行比较。 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. 删除临时文件,并将值0(成功)返回给调用者。

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 6

Before retrying, we sleep for n seconds. 在重试之前,我们睡了n秒钟。 n is initially 5 seconds, but after every retry 5 extra seconds is added up to a maximum of 60 seconds (an incremental backoff). n最初为5秒,但在每次重试后,额外增加5秒,最多为60秒(增量退避)。 Then we go to step 2 up to retries times. 然后我们转到第2步重试次数。

There seems to be an equivalent package called lockfile-progs on redhat . redhat上似乎有一个名为lockfile-progs的等效包。

On mac you could use lockfile and do something like: 在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"])

In your case maybe using a socket would work: 在您的情况下,使用套接字可能会工作:

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM