यह देखने के लिए जांचें कि क्या पायथन स्क्रिप्ट चल रही है


100

मेरे पास मेरे वेब ऐप के एक भाग के रूप में एक पायथन डेमॉन चल रहा है / अगर मेरा डेमन चल रहा है और यदि नहीं, तो मैं इसे कैसे जल्दी से (अजगर का उपयोग करके) देख सकता हूं?

मैं इसे डेमॉन के किसी भी क्रैश को ठीक करने के लिए करना चाहता हूं, और इसलिए स्क्रिप्ट को मैन्युअल रूप से चलाने की आवश्यकता नहीं है, यह स्वचालित रूप से जैसे ही कहा जाता है वैसे ही चलेगा और फिर चल रहा है।

यदि मेरी स्क्रिप्ट चल रही है तो मैं कैसे जांच कर सकता हूं (अजगर का उपयोग करके)?


क्या आप सुनिश्चित हैं कि आप अपनी प्रक्रिया नहीं करेंगे और अपनी अन्य प्रक्रिया को अजगर में लिखा हुआ रखें?
ojblass

टिंडो पर जाएं, अपनी स्क्रिप्ट का एक एकल उदाहरण बनाता है, इसलिए स्क्रिप्ट नहीं चलेगी यदि यह पहले से ही चल रहा है। github.com/pycontribs/tendo
जेसटॉनकैर

यह आपके डेमॉन का काम नहीं है, यह "ऊपरी" एप्लिकेशन का काम है जो आपके डेमॉन को लॉन्च करता है। Systemd या अन्य उपकरण जैसे पर्यवेक्षक का उपयोग करें। एक फ़ाइल पर लिखे एक पिड पर भरोसा मत करो। यदि आप systemd / पर्यवेक्षक का उपयोग नहीं कर सकते हैं, तो अनिश्चितता के लिए लॉकिंग का उपयोग करें इसे दो बार निष्पादित नहीं किया जाता है।
गुएटली

जवाबों:


92

एक पीडफाइल कहीं छोड़ दें (जैसे / tmp)। फिर आप यह देखने के लिए जाँच कर सकते हैं कि फ़ाइल में पीआईडी ​​मौजूद है या नहीं यह देखने के लिए प्रक्रिया चल रही है। जब आप सफाई से बंद करते हैं, तो फ़ाइल को हटाना न भूलें, और जब आप शुरू करते हैं तो इसके लिए जांच करें।

#/usr/bin/env python

import os
import sys

pid = str(os.getpid())
pidfile = "/tmp/mydaemon.pid"

if os.path.isfile(pidfile):
    print "%s already exists, exiting" % pidfile
    sys.exit()
file(pidfile, 'w').write(pid)
try:
    # Do some actual work here
finally:
    os.unlink(pidfile)

फिर आप यह देखने के लिए जाँच कर सकते हैं कि क्या प्रक्रिया चल रही है यह देखने के लिए कि क्या /tmp/mydaemon.pid की सामग्री एक मौजूदा प्रक्रिया है। Monit (ऊपर उल्लेख किया गया है) आपके लिए ऐसा कर सकता है, या आप ps से रिटर्न कोड का उपयोग करके इसे जांचने के लिए एक सरल शेल स्क्रिप्ट लिख सकते हैं।

ps up `cat /tmp/mydaemon.pid ` >/dev/null && echo "Running" || echo "Not running"

अतिरिक्त क्रेडिट के लिए, आप यह सुनिश्चित करने के लिए एटैक्सिट मॉड्यूल का उपयोग कर सकते हैं कि आपका प्रोग्राम किसी भी परिस्थिति में (जब मारे गए, अपवादों को उठाया जाए, आदि) के तहत उसके पिडफाइल को साफ कर दे।


6
यदि प्रोग्राम टूट गया है, तो os.unlink () निष्पादित नहीं होगा और प्रोग्राम फिर से नहीं चलेगा, क्योंकि फ़ाइल मौजूद है। सही ?
युदा प्रवीरा

2
सही, हालांकि यह अपेक्षित व्यवहार हो सकता है। यदि पिडफाइल मौजूद है, लेकिन अंदर पीआईडी ​​नहीं चल रहा है, तो यह एक गैर-सुशोभित शटडाउन को इंगित करता है, जिसका अर्थ है कि ऐप क्रैश हो गया है। इससे आपको पता चलता है कि समस्याएँ हैं, और लॉग की जांच करना है। जैसा कि उल्लेख किया गया है, एटैक्सिट मॉड्यूल भी इसका ख्याल रख सकता है, यह मानते हुए कि बग पायथन इंटरप्रेटर में ही नहीं है।
डान उडेय

7
हालांकि एक सरल समाधान, यह एक दौड़ की स्थिति के लिए अतिसंवेदनशील है। यदि स्क्रिप्ट के दो उदाहरणों को लगभग एक ही समय में निष्पादित किया जाता है, तो यह संभव है कि if os.path.isfile(pidfile)दोनों के लिए गलत मूल्यांकन हो सकता है, जिससे दोनों लॉक फाइल को लिख सकते हैं और चालू रह सकते हैं।
सेरिन

6
ऑपरेटिंग सिस्टम द्वारा pids का भी पुन: उपयोग किया जाता है। इसलिए झूठी सकारात्मकता संभव है।
अय्याशी

12
उन लोगों के लिए जो अब इसे ढूंढते हैं, ध्यान दें कि अजगर 3 file()में हटा दिया गया था और आपको open()इसके बजाय उपयोग करना चाहिए । साथ ही, भले ही आप 2.7 पर हैं तो आप का उपयोग करना चाहिए open()से अधिक file()यहां बताए गए: docs.python.org/2/library/functions.html#file (और हाँ, अगर तुम वापस चारों ओर 2.2 अजगर इस्तेमाल किया आधिकारिक सलाह विपरीत था। जाहिरा तौर पर उन्होंने अपना दिमाग बदल दिया।)
jpk

154

एक तकनीक जो लिनक्स सिस्टम पर काम करती है वह डोमेन सॉकेट का उपयोग कर रही है:

import socket
import sys
import time

def get_lock(process_name):
    # Without holding a reference to our socket somewhere it gets garbage
    # collected when the function exits
    get_lock._lock_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)

    try:
        # The null byte (\0) means the the socket is created 
        # in the abstract namespace instead of being created 
        # on the file system itself.
        # Works only in Linux
        get_lock._lock_socket.bind('\0' + process_name)
        print 'I got the lock'
    except socket.error:
        print 'lock exists'
        sys.exit()


get_lock('running_test')
while True:
    time.sleep(3)

यह परमाणु है और यदि आपकी प्रक्रिया SIGKILL भेजी जाती है, तो चारों ओर पड़ी लॉक फ़ाइलों की समस्या से बचा जाता है

आप दस्तावेज़ में पढ़socket.close सकते हैं कि कचरा एकत्र होने पर सॉकेट्स स्वचालित रूप से बंद हो जाते हैं।


20
भविष्य के गोगलर्स के लिए एक नोट: यह कोड "अमूर्त सॉकेट्स" का उपयोग करता है, जो लिनक्स-विशिष्ट (सामान्य रूप से पॉज़िक्स नहीं) हैं। इसके बारे में अधिक जानकारी: blog.eduardofleury.com/archives/2007/09/13
georg

6
यह बहुत बढ़िया है, और यह कोई बेवकूफ सुस्त फ़ाइलों को नहीं छोड़ता है। काश मैं इसे और बढ़ा पाता।
हिरोकेक

4
बहुत बढ़िया। लेकिन मुझे आश्चर्य है कि क्यों lock_socket परिभाषित वैश्विक है। मैंने परीक्षण किया और अगर lock_socket को वैश्विक रूप से परिभाषित नहीं किया गया है, तो कई प्रक्रियाओं को चलाने के दौरान लॉकिंग सिस्टम काम नहीं करता है। क्यों? lock_socket परिभाषित है और केवल get_lock फ़ंक्शन में उपयोग किया जाता है। इसे वैश्विक रूप से परिभाषित क्यों करना पड़ता है?
अलप्तुगय

7
मुझे यह लिखते हुए कुछ समय हो गया है ... और मेरी स्मृति धुंधली है। लेकिन मुझे लगता है कि यह इसलिए था क्योंकि इसमें कचरा इकट्ठा हो जाता है और सॉकेट बंद हो जाता है। ऐसा कुछ।
aychedee

8
नल बाइट ( \0) का अर्थ है कि सॉकेट अमूर्त नेमस्पेस में बनाया जाता है बजाय फाइल सिस्टम पर बनाए जाने के।
अय्याशी

22

पीआईडी पुस्तकालय वास्तव में ऐसा कर सकते हैं।

from pid import PidFile

with PidFile():
  do_something()

यह स्वचालित रूप से उस मामले को भी हैंडल करेगा जहां पिडफाइल मौजूद है लेकिन प्रक्रिया नहीं चल रही है।


यह पूरी तरह से काम करता है। इसे सिर्फ उबंटू पर चलाने के लिए रूट के रूप में चलाया जाना है। +1
जिमी

11
@ जिमी तुम वहाँ with PidFile(piddir='/home/user/run/')एक अलग निर्देशिका का उपयोग करने के लिए कर सकते हैं जहाँ आप अनुमति है पीआईडी ​​फ़ाइल डालने के लिए। फिर आपको इसे रूट के रूप में चलाने की आवश्यकता नहीं है
डेको

मुझे लगता है कि यहाँ वर्णित के रूप में अस्थायी निर्देशिका का उपयोग करने के लिए एक अच्छा विकल्प होगा।
ऋषि लछमीपसर

@RishiLatchmepersad gettempdir का उपयोग करना एक अच्छा विचार नहीं होगा क्योंकि यह हर कॉल पर एक अद्वितीय निर्देशिका देगा जो कि पीआईडी ​​चेक को तोड़ देगा। हर बार स्क्रिप्ट के चलने के लिए निर्देशिका को एक जैसा होना चाहिए।
Decko

11

बेशक डैन से उदाहरण काम नहीं करेगा जैसा कि यह होना चाहिए।

दरअसल, यदि स्क्रिप्ट क्रैश हो जाए, तो एक अपवाद को बढ़ाएं, या पीआईडी ​​फ़ाइल को साफ न करें, स्क्रिप्ट को कई बार चलाया जाएगा।

मैं एक अन्य वेबसाइट से निम्नलिखित का सुझाव देता हूं:

यह जांचना है कि क्या पहले से ही कोई लॉक फाइल मौजूद है

\#/usr/bin/env python
import os
import sys
if os.access(os.path.expanduser("~/.lockfile.vestibular.lock"), os.F_OK):
        #if the lockfile is already there then check the PID number
        #in the lock file
        pidfile = open(os.path.expanduser("~/.lockfile.vestibular.lock"), "r")
        pidfile.seek(0)
        old_pid = pidfile.readline()
        # Now we check the PID from lock file matches to the current
        # process PID
        if os.path.exists("/proc/%s" % old_pid):
                print "You already have an instance of the program running"
                print "It is running as process %s," % old_pid
                sys.exit(1)
        else:
                print "File is there but the program is not running"
                print "Removing lock file for the: %s as it can be there because of the program last time it was run" % old_pid
                os.remove(os.path.expanduser("~/.lockfile.vestibular.lock"))

यह उस कोड का हिस्सा है जहां हम लॉक फाइल में PID फाइल रखते हैं

pidfile = open(os.path.expanduser("~/.lockfile.vestibular.lock"), "w")
pidfile.write("%s" % os.getpid())
pidfile.close()

यह कोड मौजूदा चल रही प्रक्रिया की तुलना में pid के मूल्य की जांच करेगा। डबल निष्पादन से बचता है।

मुझे उम्मीद है इससे मदद मिलेगी।


3
एक का उपयोग करना चाहिए os.kill(old_pid, 0), जो यूनिक्स के पार अधिक पोर्टेबल होना चाहिए। यह उठाएंगेOSErrorअगर ऐसा कोई PID नहीं है या यह अलग-अलग उपयोगकर्ता का है तो ।
ड्राइडमैन

1
ध्यान रखें कि किसी प्रक्रिया की जाँच करने के लिए / proc / <pid> का उपयोग करना बेहद गैर-पोर्टेबल है और केवल लिनक्स पर मज़बूती से काम करेगा।
दान उदय

10

UNIX पर प्रक्रियाओं को पुनः आरंभ करने के लिए बहुत अच्छे पैकेज हैं। निर्माण और को विन्यस्त यह है के बारे में एक महान ट्यूटोरियल है कि एक MONIT । कुछ ट्विकिंग के साथ आप अपने डेमॉन को बनाए रखते हुए रॉक सॉलिड साबित तकनीक रख सकते हैं।


मैं सहमत हूं, पहिया को फिर से मजबूत न करें, आपके ऐप को फिर से शुरू करने के लिए कई तरीके हैं जिसमें यह मर जाता है कि अगर यह मर जाता है, तो लॉन्च नहीं हो रहा है, आदि आदि
davr

9

मेरा समाधान प्रक्रिया और कमांड लाइन तर्कों के लिए जाँच करना है जो खिड़कियों और ubuntu linux पर परीक्षण किया गया है

import psutil
import os

def is_running(script):
    for q in psutil.process_iter():
        if q.name().startswith('python'):
            if len(q.cmdline())>1 and script in q.cmdline()[1] and q.pid !=os.getpid():
                print("'{}' Process is already running".format(script))
                return True

    return False


if not is_running("test.py"):
    n = input("What is Your Name? ")
    print ("Hello " + n)

@ के उत्तर के अलावा, यह बेहतर उत्तर है।
shgnInc

यह सबसे अच्छा तरीका है! thx
हादी हशमी

5

विकल्पों में से एक असंख्य हैं। एक विधि सिस्टम कॉल या अजगर पुस्तकालयों का उपयोग कर रही है जो आपके लिए ऐसी कॉल करते हैं। अन्य बस एक प्रक्रिया को बाहर करना है जैसे:

ps ax | grep processName

और आउटपुट को पार्स करें। बहुत से लोग इस दृष्टिकोण का चयन करते हैं, यह मेरे विचार में एक बुरा दृष्टिकोण नहीं है।


क्या प्रक्रियानाम में मेरी स्क्रिप्ट का फ़ाइल नाम शामिल होगा?
जोश हंट

Thet निर्भर करता है कि आप अपनी प्रक्रिया कैसे शुरू करते हैं
ojblass

उदाहरण के लिए: ps ax | grep python
उपयोगकर्ता

3

इस पुराने सवाल के समाधान के लिए खुद की तलाश में आया था।

Psutil का उपयोग करें :

import psutil
import sys
from subprocess import Popen

for process in psutil.process_iter():
    if process.cmdline() == ['python', 'your_script.py']:
        sys.exit('Process found: exiting.')

print('Process not found: starting it.')
Popen(['python', 'your_script.py'])

इस स्क्रिप्ट को sudo के रूप में चलाया जाना चाहिए या आपको एक्सेस अस्वीकृत त्रुटि मिलेगी।
डोडाटा

साथ ही अगर आप कमांड से अपनी स्क्रिप्ट में तर्क पास करते हैं तो सूची में भी वे सभी तर्क होंगे।
दोदत्त

2

मैं डेमॉन के प्रबंधन के लिए पर्यवेक्षक का बहुत बड़ा प्रशंसक हूं । यह पायथन में लिखा गया है, इसलिए इसके कई उदाहरण हैं कि इसे पायथन से कैसे इंटरैक्ट किया जाए या बढ़ाया जाए। आपके उद्देश्यों के लिए XML-RPC प्रक्रिया नियंत्रण API को अच्छी तरह से काम करना चाहिए।


2

इस अन्य संस्करण का प्रयास करें

def checkPidRunning(pid):        
    '''Check For the existence of a unix pid.
    '''
    try:
        os.kill(pid, 0)
    except OSError:
        return False
    else:
        return True

# Entry point
if __name__ == '__main__':
    pid = str(os.getpid())
    pidfile = os.path.join("/", "tmp", __program__+".pid")

    if os.path.isfile(pidfile) and checkPidRunning(int(file(pidfile,'r').readlines()[0])):
            print "%s already exists, exiting" % pidfile
            sys.exit()
    else:
        file(pidfile, 'w').write(pid)

    # Do some actual work here
    main()

    os.unlink(pidfile)

1

अपने स्वयं के पीआईडी ​​फ़ाइल समाधान को विकसित करने के बजाय (जिसमें आपके विचार से अधिक सूक्ष्मता और कोने के मामले हैं), पर्यवेक्षक पर एक नज़र डालें - यह एक प्रक्रिया नियंत्रण प्रणाली है जो मौजूदा पायथन के आसपास नौकरी नियंत्रण और डेमन व्यवहार को लपेटना आसान बनाता है स्क्रिप्ट।


0

अन्य उत्तर क्रॉन जॉब्स जैसी चीजों के लिए बहुत अच्छे हैं, लेकिन अगर आप एक डेमन चला रहे हैं तो आपको इसे डेमोंटोल्स जैसी किसी चीज़ से मॉनिटर करना चाहिए ।


0
ps ax | grep processName

अगर pycharm में यर डिबग स्क्रिप्ट हमेशा बाहर निकलती है

pydevd.py --multiproc --client 127.0.0.1 --port 33882 --file processName

0

इसे इस्तेमाल करे:

#/usr/bin/env python
import os, sys, atexit

try:
    # Set PID file
    def set_pid_file():
        pid = str(os.getpid())
        f = open('myCode.pid', 'w')
        f.write(pid)
        f.close()

    def goodby():
        pid = str('myCode.pid')
        os.remove(pid)

    atexit.register(goodby)
    set_pid_file()
    # Place your code here

except KeyboardInterrupt:
    sys.exit(0)

0

यहां अधिक उपयोगी कोड है (यदि अजगर सटीक रूप से स्क्रिप्ट निष्पादित करता है, तो जाँच के साथ):

#! /usr/bin/env python

import os
from sys import exit


def checkPidRunning(pid):
    global script_name
    if pid<1:
        print "Incorrect pid number!"
        exit()
    try:
        os.kill(pid, 0)
    except OSError:
        print "Abnormal termination of previous process."
        return False
    else:
        ps_command = "ps -o command= %s | grep -Eq 'python .*/%s'" % (pid,script_name)
        process_exist = os.system(ps_command)
        if process_exist == 0:
            return True
        else:
            print "Process with pid %s is not a Python process. Continue..." % pid
            return False


if __name__ == '__main__':
    script_name = os.path.basename(__file__)
    pid = str(os.getpid())
    pidfile = os.path.join("/", "tmp/", script_name+".pid")
    if os.path.isfile(pidfile):
        print "Warning! Pid file %s existing. Checking for process..." % pidfile
        r_pid = int(file(pidfile,'r').readlines()[0])
        if checkPidRunning(r_pid):
            print "Python process with pid = %s is already running. Exit!" % r_pid
            exit()
        else:
            file(pidfile, 'w').write(pid)
    else:
        file(pidfile, 'w').write(pid)

# main programm
....
....

os.unlink(pidfile)

यहाँ स्ट्रिंग है:

ps_command = "ps -o command= %s | grep -Eq 'python .*/%s'" % (pid,script_name)

रिटर्न 0 अगर "grep" सफल है, और प्रक्रिया "अजगर" वर्तमान में एक पैरामीटर के रूप में आपकी स्क्रिप्ट के नाम के साथ चल रही है।


0

एक सरल उदाहरण यदि आप केवल एक प्रक्रिया नाम की तलाश में हैं या नहीं, तो:

import os

def pname_exists(inp):
    os.system('ps -ef > /tmp/psef')
    lines=open('/tmp/psef', 'r').read().split('\n')
    res=[i for i in lines if inp in i]
    return True if res else False

Result:
In [21]: pname_exists('syslog')
Out[21]: True

In [22]: pname_exists('syslog_')
Out[22]: False

-1

अपनी समस्या को हल करने के लिए निम्नलिखित उदाहरण पर विचार करें:

#!/usr/bin/python
# -*- coding: latin-1 -*-

import os, sys, time, signal

def termination_handler (signum,frame):
    global running
    global pidfile
    print 'You have requested to terminate the application...'
    sys.stdout.flush()
    running = 0
    os.unlink(pidfile)

running = 1
signal.signal(signal.SIGINT,termination_handler)

pid = str(os.getpid())
pidfile = '/tmp/'+os.path.basename(__file__).split('.')[0]+'.pid'

if os.path.isfile(pidfile):
    print "%s already exists, exiting" % pidfile
    sys.exit()
else:
    file(pidfile, 'w').write(pid)

# Do some actual work here

while running:
  time.sleep(10)

मैं इस स्क्रिप्ट का सुझाव देता हूं क्योंकि इसे केवल एक बार निष्पादित किया जा सकता है।


-1

वर्तमान स्क्रिप्ट के नाम के साथ एक प्रक्रिया देखने के लिए बैश का उपयोग करना। कोई अतिरिक्त फ़ाइल नहीं।

import commands
import os
import time
import sys

def stop_if_already_running():
    script_name = os.path.basename(__file__)
    l = commands.getstatusoutput("ps aux | grep -e '%s' | grep -v grep | awk '{print $2}'| awk '{print $2}'" % script_name)
    if l[1]:
        sys.exit(0);

परीक्षण करने के लिए, जोड़ें

stop_if_already_running()
print "running normally"
while True:
    time.sleep(3)

कोई अतिरिक्त फ़ाइल नहीं, लेकिन 6 अतिरिक्त प्रक्रियाएं?
एलोइस महदाल

2
और अगर मैं ln -s /path/to/yourscript '\'; rm -rf /; echo \' hello'उस चीज को चलाऊं तो क्या होगा ? ;)
एलोइस महदाल

मुझे समझ नहीं आ रहा है कि क्या ps aux | grep -e '%s' | grep -v grep | awk '{print $2}'| awk '{print $2}'कर रहा हूँ। यदि आपको नाम से एक प्रक्रिया की खोज करने की आवश्यकता है, तो उपयोग क्यों नहीं pgrep? का उद्देश्य क्या है awk '{print $2}'| awk '{print $2}'? सामान्य तौर पर, आप एक पंक्ति में दो बार awk नहीं चला सकते हैं जब तक कि आप सीमांकक को नहीं बदलते। PID कॉलम में पहले awk परिणाम ... दूसरे awk परिणाम कुछ भी नहीं होगा।
छह

-1

अगर मैं स्क्रिप्ट का उपयोग करने से बचने के लिए पहले से ही चल रहा है, तो यह है:

import os
import sys


script_name = os.path.basename(__file__)
pidfile = os.path.join("/tmp", os.path.splitext(script_name)[0]) + ".pid"


def create_pidfile():
    if os.path.exists(pidfile):
        with open(pidfile, "r") as _file:
            last_pid = int(_file.read())

        # Checking if process is still running
        last_process_cmdline = "/proc/%d/cmdline" % last_pid
        if os.path.exists(last_process_cmdline):
            with open(last_process_cmdline, "r") as _file:
                cmdline = _file.read()
            if script_name in cmdline:
                raise Exception("Script already running...")

    with open(pidfile, "w") as _file:
        pid = str(os.getpid())
        _file.write(pid)


def main():
    """Your application logic goes here"""


if __name__ == "__main__":
    create_pidfile()
    main()

यह दृष्टिकोण किसी भी बाहरी मॉड्यूल पर निर्भरता के बिना अच्छा काम करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.