如何使 Python 脚本像 Linux 中的服务或守护进程一样运行

发布于 2024-08-08 10:29:33 字数 128 浏览 9 评论 0原文

我编写了一个 Python 脚本来检查某个电子邮件地址并将新电子邮件传递给外部程序。我怎样才能让这个脚本24/7执行,比如把它变成Linux中的守护进程或服务。我是否还需要一个在程序中永远不会结束的循环,或者可以通过多次重新执行代码来完成吗?

I have written a Python script that checks a certain e-mail address and passes new e-mails to an external program. How can I get this script to execute 24/7, such as turning it into daemon or service in Linux. Would I also need a loop that never ends in the program, or can it be done by just having the code re executed multiple times?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

人疚 2024-08-15 10:29:33

这里你有两个选择。

  1. 创建一个适当的cron 作业来调用您的脚本。 Cron 是 GNU/Linux 守护程序的通用名称,它根据您设置的时间表定期启动脚本。您将脚本添加到 crontab 中或将其符号链接放置到特殊目录中,守护程序将处理在后台启动它的工作。您可以在维基百科上了解更多内容。有多种不同的 cron 守护进程,但您的 GNU/Linux 系统应该已经安装了它。

  2. 使用某种python 方法(例如,一个库)让您的脚本能够自行守护进程。是的,它将需要一个简单的事件循环(其中您的事件是计时器触发,可能由睡眠函数提供)。

我不建议您选择 2.,因为实际上您会重复 cron 功能。 Linux系统范式是让多个简单的工具交互并解决你的问题。除非有其他原因需要创建守护程序(除了定期触发),否则请选择其他方法。

另外,如果您在循环中使用 daemonize 并且发生崩溃,则此后没有人会检查邮件(正如 Ivan 所指出的) Nevostruev 在对 这个答案)。而如果脚本被添加为 cron 作业,它只会再次触发。

You have two options here.

  1. Make a proper cron job that calls your script. Cron is a common name for a GNU/Linux daemon that periodically launches scripts according to a schedule you set. You add your script into a crontab or place a symlink to it into a special directory and the daemon handles the job of launching it in the background. You can read more at Wikipedia. There is a variety of different cron daemons, but your GNU/Linux system should have it already installed.

  2. Use some kind of python approach (a library, for example) for your script to be able to daemonize itself. Yes, it will require a simple event loop (where your events are timer triggering, possibly, provided by sleep function).

I wouldn't recommend you to choose 2., because you would be, in fact, repeating cron functionality. The Linux system paradigm is to let multiple simple tools interact and solve your problems. Unless there are additional reasons why you should make a daemon (in addition to trigger periodically), choose the other approach.

Also, if you use daemonize with a loop and a crash happens, no one will check the mail after that (as pointed out by Ivan Nevostruev in comments to this answer). While if the script is added as a cron job, it will just trigger again.

挽心 2024-08-15 10:29:33

这是一个很好的课程,取自

#!/usr/bin/env python

import sys, os, time, atexit
from signal import SIGTERM

class Daemon:
        """
        A generic daemon class.

        Usage: subclass the Daemon class and override the run() method
        """
        def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
                self.stdin = stdin
                self.stdout = stdout
                self.stderr = stderr
                self.pidfile = pidfile

        def daemonize(self):
                """
                do the UNIX double-fork magic, see Stevens' "Advanced
                Programming in the UNIX Environment" for details (ISBN 0201563177)
                http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
                """
                try:
                        pid = os.fork()
                        if pid > 0:
                                # exit first parent
                                sys.exit(0)
                except OSError, e:
                        sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
                        sys.exit(1)

                # decouple from parent environment
                os.chdir("/")
                os.setsid()
                os.umask(0)

                # do second fork
                try:
                        pid = os.fork()
                        if pid > 0:
                                # exit from second parent
                                sys.exit(0)
                except OSError, e:
                        sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
                        sys.exit(1)

                # redirect standard file descriptors
                sys.stdout.flush()
                sys.stderr.flush()
                si = file(self.stdin, 'r')
                so = file(self.stdout, 'a+')
                se = file(self.stderr, 'a+', 0)
                os.dup2(si.fileno(), sys.stdin.fileno())
                os.dup2(so.fileno(), sys.stdout.fileno())
                os.dup2(se.fileno(), sys.stderr.fileno())

                # write pidfile
                atexit.register(self.delpid)
                pid = str(os.getpid())
                file(self.pidfile,'w+').write("%s\n" % pid)

        def delpid(self):
                os.remove(self.pidfile)

        def start(self):
                """
                Start the daemon
                """
                # Check for a pidfile to see if the daemon already runs
                try:
                        pf = file(self.pidfile,'r')
                        pid = int(pf.read().strip())
                        pf.close()
                except IOError:
                        pid = None

                if pid:
                        message = "pidfile %s already exist. Daemon already running?\n"
                        sys.stderr.write(message % self.pidfile)
                        sys.exit(1)

                # Start the daemon
                self.daemonize()
                self.run()

        def stop(self):
                """
                Stop the daemon
                """
                # Get the pid from the pidfile
                try:
                        pf = file(self.pidfile,'r')
                        pid = int(pf.read().strip())
                        pf.close()
                except IOError:
                        pid = None

                if not pid:
                        message = "pidfile %s does not exist. Daemon not running?\n"
                        sys.stderr.write(message % self.pidfile)
                        return # not an error in a restart

                # Try killing the daemon process       
                try:
                        while 1:
                                os.kill(pid, SIGTERM)
                                time.sleep(0.1)
                except OSError, err:
                        err = str(err)
                        if err.find("No such process") > 0:
                                if os.path.exists(self.pidfile):
                                        os.remove(self.pidfile)
                        else:
                                print str(err)
                                sys.exit(1)

        def restart(self):
                """
                Restart the daemon
                """
                self.stop()
                self.start()

        def run(self):
                """
                You should override this method when you subclass Daemon. It will be called after the process has been
                daemonized by start() or restart().
                """

Here's a nice class that is taken from here:

#!/usr/bin/env python

import sys, os, time, atexit
from signal import SIGTERM

class Daemon:
        """
        A generic daemon class.

        Usage: subclass the Daemon class and override the run() method
        """
        def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
                self.stdin = stdin
                self.stdout = stdout
                self.stderr = stderr
                self.pidfile = pidfile

        def daemonize(self):
                """
                do the UNIX double-fork magic, see Stevens' "Advanced
                Programming in the UNIX Environment" for details (ISBN 0201563177)
                http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
                """
                try:
                        pid = os.fork()
                        if pid > 0:
                                # exit first parent
                                sys.exit(0)
                except OSError, e:
                        sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
                        sys.exit(1)

                # decouple from parent environment
                os.chdir("/")
                os.setsid()
                os.umask(0)

                # do second fork
                try:
                        pid = os.fork()
                        if pid > 0:
                                # exit from second parent
                                sys.exit(0)
                except OSError, e:
                        sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
                        sys.exit(1)

                # redirect standard file descriptors
                sys.stdout.flush()
                sys.stderr.flush()
                si = file(self.stdin, 'r')
                so = file(self.stdout, 'a+')
                se = file(self.stderr, 'a+', 0)
                os.dup2(si.fileno(), sys.stdin.fileno())
                os.dup2(so.fileno(), sys.stdout.fileno())
                os.dup2(se.fileno(), sys.stderr.fileno())

                # write pidfile
                atexit.register(self.delpid)
                pid = str(os.getpid())
                file(self.pidfile,'w+').write("%s\n" % pid)

        def delpid(self):
                os.remove(self.pidfile)

        def start(self):
                """
                Start the daemon
                """
                # Check for a pidfile to see if the daemon already runs
                try:
                        pf = file(self.pidfile,'r')
                        pid = int(pf.read().strip())
                        pf.close()
                except IOError:
                        pid = None

                if pid:
                        message = "pidfile %s already exist. Daemon already running?\n"
                        sys.stderr.write(message % self.pidfile)
                        sys.exit(1)

                # Start the daemon
                self.daemonize()
                self.run()

        def stop(self):
                """
                Stop the daemon
                """
                # Get the pid from the pidfile
                try:
                        pf = file(self.pidfile,'r')
                        pid = int(pf.read().strip())
                        pf.close()
                except IOError:
                        pid = None

                if not pid:
                        message = "pidfile %s does not exist. Daemon not running?\n"
                        sys.stderr.write(message % self.pidfile)
                        return # not an error in a restart

                # Try killing the daemon process       
                try:
                        while 1:
                                os.kill(pid, SIGTERM)
                                time.sleep(0.1)
                except OSError, err:
                        err = str(err)
                        if err.find("No such process") > 0:
                                if os.path.exists(self.pidfile):
                                        os.remove(self.pidfile)
                        else:
                                print str(err)
                                sys.exit(1)

        def restart(self):
                """
                Restart the daemon
                """
                self.stop()
                self.start()

        def run(self):
                """
                You should override this method when you subclass Daemon. It will be called after the process has been
                daemonized by start() or restart().
                """
三生池水覆流年 2024-08-15 10:29:33

假设您确实希望循环作为后台服务 24/7 运行

对于不涉及使用库注入代码的解决方案,您可以简单地创建一个服务模板,因为您正在使用linux:

[Unit]
Description = <Your service description here>
After = network.target # Assuming you want to start after network interfaces are made available
 
[Service]
Type = simple
ExecStart = python <Path of the script you want to run>
User = # User to run the script as
Group = # Group to run the script as
Restart = on-failure # Restart when there are errors
SyslogIdentifier = <Name of logs for the service>
RestartSec = 5
TimeoutStartSec = infinity
 
[Install]
WantedBy = multi-user.target # Make it accessible to other users

将该文件放在守护程序服务文件夹(通常为 /etc/systemd/system/)中的 *.service 文件中,并使用以下 systemctl 命令安装它(可能需要 sudo 权限):

systemctl enable <service file name without .service extension>

systemctl daemon-reload

systemctl start <service file name without .service extension>

然后您可以使用以下命令检查您的服务是否正在运行:

systemctl | grep running

Assuming that you would really want your loop to run 24/7 as a background service

For a solution that doesn't involve injecting your code with libraries, you can simply create a service template, since you are using linux:

[Unit]
Description = <Your service description here>
After = network.target # Assuming you want to start after network interfaces are made available
 
[Service]
Type = simple
ExecStart = python <Path of the script you want to run>
User = # User to run the script as
Group = # Group to run the script as
Restart = on-failure # Restart when there are errors
SyslogIdentifier = <Name of logs for the service>
RestartSec = 5
TimeoutStartSec = infinity
 
[Install]
WantedBy = multi-user.target # Make it accessible to other users

Place that file in your daemon service folder (usually /etc/systemd/system/), in a *.service file, and install it using the following systemctl commands (will likely require sudo privileges):

systemctl enable <service file name without .service extension>

systemctl daemon-reload

systemctl start <service file name without .service extension>

You can then check that your service is running by using the command:

systemctl | grep running
时常饿 2024-08-15 10:29:33

您应该使用 python-daemon 库,它会处理一切。

来自 PyPI:用于实现行为良好的 Unix 守护进程的库。

You should use the python-daemon library, it takes care of everything.

From PyPI: Library to implement a well-behaved Unix daemon process.

白昼 2024-08-15 10:29:33

您可以使用 fork() 将脚本与 tty 分离并让它继续运行,如下所示:

import os, sys
fpid = os.fork()
if fpid!=0:
  # Running as daemon now. PID is fpid
  sys.exit(0)

当然您还需要实现一个无限循环,例如

while 1:
  do_your_check()
  sleep(5)

希望这能让您开始。

You can use fork() to detach your script from the tty and have it continue to run, like so:

import os, sys
fpid = os.fork()
if fpid!=0:
  # Running as daemon now. PID is fpid
  sys.exit(0)

Of course you also need to implement an endless loop, like

while 1:
  do_your_check()
  sleep(5)

Hope this get's you started.

我三岁 2024-08-15 10:29:33

一个简单且受支持的版本Daemonize

从 Python Package Index (PyPI) 安装它:

$ pip install daemonize

然后使用如下:

...
import os, sys
from daemonize import Daemonize
...
def main()
      # your code here

if __name__ == '__main__':
        myname=os.path.basename(sys.argv[0])
        pidfile='/tmp/%s' % myname       # any name
        daemon = Daemonize(app=myname,pid=pidfile, action=main)
        daemon.start()

A simple and supported version is Daemonize.

Install it from Python Package Index (PyPI):

$ pip install daemonize

and then use like:

...
import os, sys
from daemonize import Daemonize
...
def main()
      # your code here

if __name__ == '__main__':
        myname=os.path.basename(sys.argv[0])
        pidfile='/tmp/%s' % myname       # any name
        daemon = Daemonize(app=myname,pid=pidfile, action=main)
        daemon.start()
猫性小仙女 2024-08-15 10:29:33

您还可以使用 shell 脚本使 python 脚本作为服务运行。首先创建一个 shell 脚本来运行 python 脚本,如下所示(scriptname 任意名称)

#!/bin/sh
script='/home/.. full path to script'
/usr/bin/python $script &

现在在 /etc/init.d/scriptname 中创建一个文件

#! /bin/sh

PATH=/bin:/usr/bin:/sbin:/usr/sbin
DAEMON=/home/.. path to shell script scriptname created to run python script
PIDFILE=/var/run/scriptname.pid

test -x $DAEMON || exit 0

. /lib/lsb/init-functions

case "$1" in
  start)
     log_daemon_msg "Starting feedparser"
     start_daemon -p $PIDFILE $DAEMON
     log_end_msg $?
   ;;
  stop)
     log_daemon_msg "Stopping feedparser"
     killproc -p $PIDFILE $DAEMON
     PID=`ps x |grep feed | head -1 | awk '{print $1}'`
     kill -9 $PID       
     log_end_msg $?
   ;;
  force-reload|restart)
     $0 stop
     $0 start
   ;;
  status)
     status_of_proc -p $PIDFILE $DAEMON atd && exit 0 || exit $?
   ;;
 *)
   echo "Usage: /etc/init.d/atd {start|stop|restart|force-reload|status}"
   exit 1
  ;;
esac

exit 0

现在您可以使用命令 /etc/init.d/scriptname 启动和停止 python 脚本开始或停止。

You can also make the python script run as a service using a shell script. First create a shell script to run the python script like this (scriptname arbitary name)

#!/bin/sh
script='/home/.. full path to script'
/usr/bin/python $script &

now make a file in /etc/init.d/scriptname

#! /bin/sh

PATH=/bin:/usr/bin:/sbin:/usr/sbin
DAEMON=/home/.. path to shell script scriptname created to run python script
PIDFILE=/var/run/scriptname.pid

test -x $DAEMON || exit 0

. /lib/lsb/init-functions

case "$1" in
  start)
     log_daemon_msg "Starting feedparser"
     start_daemon -p $PIDFILE $DAEMON
     log_end_msg $?
   ;;
  stop)
     log_daemon_msg "Stopping feedparser"
     killproc -p $PIDFILE $DAEMON
     PID=`ps x |grep feed | head -1 | awk '{print $1}'`
     kill -9 $PID       
     log_end_msg $?
   ;;
  force-reload|restart)
     $0 stop
     $0 start
   ;;
  status)
     status_of_proc -p $PIDFILE $DAEMON atd && exit 0 || exit $?
   ;;
 *)
   echo "Usage: /etc/init.d/atd {start|stop|restart|force-reload|status}"
   exit 1
  ;;
esac

exit 0

Now you can start and stop your python script using the command /etc/init.d/scriptname start or stop.

深爱成瘾 2024-08-15 10:29:33

对于许多用途来说,cron 显然是一个不错的选择。但是,它不会按照您在 OP 中请求的那样创建服务或守护程序。 cron 只是定期运行作业(意味着作业启动和停止),并且频率不超过每分钟一次。 cron 存在问题 - 例如,如果下次 cron 计划出现并启动新实例时,您的脚本的先前实例仍在运行,那么是不是好的? cron 不处理依赖关系;它只是尝试按照时间表开始工作。

如果您发现确实需要守护进程(一个永不停止运行的进程)的情况,请查看 supervisord。它提供了一种简单的方法来包装普通的非守护程序脚本或程序,并使其像守护程序一样运行。这是比创建本机 Python 守护程序更好的方法。

cron is clearly a great choice for many purposes. However it doesn't create a service or daemon as you requested in the OP. cron just runs jobs periodically (meaning the job starts and stops), and no more often than once / minute. There are issues with cron -- for example, if a prior instance of your script is still running the next time the cron schedule comes around and launches a new instance, is that OK? cron doesn't handle dependencies; it just tries to start a job when the schedule says to.

If you find a situation where you truly need a daemon (a process that never stops running), take a look at supervisord. It provides a simple way to wrapper a normal, non-daemonized script or program and make it operate like a daemon. This is a much better way than creating a native Python daemon.

若有似无的小暗淡 2024-08-15 10:29:33

Ubuntu 有一种非常简单的方法来管理服务。
对于 python,区别在于所有依赖项(包)必须位于运行主文件的同一目录中。

我只是设法创建这样的服务来向我的客户提供天气信息。
步骤:

  • 像平常一样创建 Python 应用程序项目。

  • 在本地安装所有依赖项,如下所示:
    sudo pip3 install package_name -t 。

  • 创建命令行变量并在代码中处理它们(如果需要)

  • 创建服务文件。一些(极简主义),例如:

    <前><代码> [单位]
    描述=1Droid 天气中间件提供商

    [服务]
    重新启动=始终
    用户=root
    工作目录=/home/ubuntu/天气
    ExecStart=/usr/bin/python3 /home/ubuntu/weather/main.py httpport=9570 提供商=OWMap

    [安装]
    WantedBy=多用户.target

  • 将文件另存为 myweather.service(例如)

  • 确保您的应用程序在当前目录中启动时运行

     python3 main.py httpport=9570 提供者=OWMap
    
  • 上面生成的名为 myweather.service 的服务文件(重要的是具有扩展名 .service)将被系统视为您的服务名称。这是您将用来与服务交互的名称。

  • 复制服务文件:

     sudo cp myweather.service /lib/systemd/system/myweather.service
    
  • 刷新恶魔注册表:

     sudo systemctl daemon-reload
    
  • 停止服务(如果它正在运行)

     sudo service myweather stop
    
  • 启动服务:

     sudo service myweather start
    
  • 检查状态(包含打印语句所在位置的日志文件):

    <前><代码> tail -f /var/log/syslog

  • 或检查状态:

     sudo service myweather 状态
    
  • 如果需要,请返回到开头进行另一次迭代

该服务现在正在运行,即使您注销它也不会受到影响。
是的,如果主机关闭并重新启动,该服务将重新启动......

Ubuntu has a very simple way to manage a service.
For python the difference is that ALL the dependencies (packages) have to be in the same directory, where the main file is run from.

I just manage to create such a service to provide weather info to my clients.
Steps:

  • Create your python application project as you normally do.

  • Install all dependencies locally like:
    sudo pip3 install package_name -t .

  • Create your command line variables and handle them in code (if you need any)

  • Create the service file. Something (minimalist) like:

      [Unit]
      Description=1Droid Weather meddleware provider
    
      [Service]
      Restart=always
      User=root
      WorkingDirectory=/home/ubuntu/weather
      ExecStart=/usr/bin/python3 /home/ubuntu/weather/main.py httpport=9570  provider=OWMap
    
      [Install]
      WantedBy=multi-user.target
    
  • Save the file as myweather.service (for example)

  • Make sure that your app runs if started in the current directory

      python3  main.py httpport=9570  provider=OWMap
    
  • The service file produced above and named myweather.service (important to have the extension .service) will be treated by the system as the name of your service. That is the name that you will use to interact with your service.

  • Copy the service file:

      sudo cp myweather.service /lib/systemd/system/myweather.service
    
  • Refresh demon registry:

      sudo systemctl daemon-reload
    
  • Stop the service (if it was running)

      sudo service myweather stop
    
  • Start the service:

      sudo service myweather start
    
  • Check the status (log file with where your print statements go):

      tail -f /var/log/syslog
    
  • Or check the status with:

      sudo service myweather status
    
  • Back to the start with another iteration if needed

This service is now running and even if you log out it will not be affected.
And YES if the host is shutdown and restarted this service will be restarted...

墨小墨 2024-08-15 10:29:33

在 Linux 上使用 $nohup 命令怎么样?

我用它在 Bluehost 服务器上运行命令。

如果我错了请指教。

how about using $nohup command on linux?

I use it for running my commands on my Bluehost server.

Please advice if I am wrong.

静谧幽蓝 2024-08-15 10:29:33

如果您使用终端(ssh 或其他),并且希望在从终端注销后保持脚本长时间运行,您可以尝试以下操作:

screen

apt-get install screen

在里面创建一个虚拟终端(即 abc): screen -dmS abc

现在我们连接到 abc: screen -r abc

所以,现在我们可以运行 python 脚本: python keep_sending_mails.py

从现在开始,您可以直接关闭终端,但是 python 脚本将继续运行而不是被关闭

因为这个 keep_sending_mails.py 的 PID 是虚拟屏幕的子进程而不是
终端(ssh)

如果你想返回检查脚本运行状态,你可以再次使用 screen -r abc

If you are using terminal(ssh or something) and you want to keep a long-time script working after you log out from the terminal, you can try this:

screen

apt-get install screen

create a virtual terminal inside( namely abc): screen -dmS abc

now we connect to abc: screen -r abc

So, now we can run python script: python keep_sending_mails.py

from now on, you can directly close your terminal, however, the python script will keep running rather than being shut down

Since this keep_sending_mails.py's PID is a child process of the virtual screen rather than the
terminal(ssh)

If you want to go back check your script running status, you can use screen -r abc again

栀子花开つ 2024-08-15 10:29:33

首先,阅读邮件别名。邮件别名将在邮件系统内执行此操作,而无需您使用守护程序或服务或任何类似的东西。

您可以编写一个简单的脚本,每次将邮件消息发送到特定邮箱时,sendmail 都会执行该脚本。

请参阅 http://www.feep.net/sendmail/tutorial/intro/aliases .html

如果你真的想编写一个不必要的复杂服务器,你可以这样做。

nohup python myscript.py &

仅此而已。您的脚本只是循环并休眠。

import time
def do_the_work():
    # one round of polling -- checking email, whatever.
while True:
    time.sleep( 600 ) # 10 min.
    try:
        do_the_work()
    except:
        pass

First, read up on mail aliases. A mail alias will do this inside the mail system without you having to fool around with daemons or services or anything of the sort.

You can write a simple script that will be executed by sendmail each time a mail message is sent to a specific mailbox.

See http://www.feep.net/sendmail/tutorial/intro/aliases.html

If you really want to write a needlessly complex server, you can do this.

nohup python myscript.py &

That's all it takes. Your script simply loops and sleeps.

import time
def do_the_work():
    # one round of polling -- checking email, whatever.
while True:
    time.sleep( 600 ) # 10 min.
    try:
        do_the_work()
    except:
        pass
乖乖哒 2024-08-15 10:29:33

我会推荐这个解决方案。您需要继承并重写方法run

import sys
import os
from signal import SIGTERM
from abc import ABCMeta, abstractmethod



class Daemon(object):
    __metaclass__ = ABCMeta


    def __init__(self, pidfile):
        self._pidfile = pidfile


    @abstractmethod
    def run(self):
        pass


    def _daemonize(self):
        # decouple threads
        pid = os.fork()

        # stop first thread
        if pid > 0:
            sys.exit(0)

        # write pid into a pidfile
        with open(self._pidfile, 'w') as f:
            print >> f, os.getpid()


    def start(self):
        # if daemon is started throw an error
        if os.path.exists(self._pidfile):
            raise Exception("Daemon is already started")

        # create and switch to daemon thread
        self._daemonize()

        # run the body of the daemon
        self.run()


    def stop(self):
        # check the pidfile existing
        if os.path.exists(self._pidfile):
            # read pid from the file
            with open(self._pidfile, 'r') as f:
                pid = int(f.read().strip())

            # remove the pidfile
            os.remove(self._pidfile)

            # kill daemon
            os.kill(pid, SIGTERM)

        else:
            raise Exception("Daemon is not started")


    def restart(self):
        self.stop()
        self.start()

I would recommend this solution. You need to inherit and override method run.

import sys
import os
from signal import SIGTERM
from abc import ABCMeta, abstractmethod



class Daemon(object):
    __metaclass__ = ABCMeta


    def __init__(self, pidfile):
        self._pidfile = pidfile


    @abstractmethod
    def run(self):
        pass


    def _daemonize(self):
        # decouple threads
        pid = os.fork()

        # stop first thread
        if pid > 0:
            sys.exit(0)

        # write pid into a pidfile
        with open(self._pidfile, 'w') as f:
            print >> f, os.getpid()


    def start(self):
        # if daemon is started throw an error
        if os.path.exists(self._pidfile):
            raise Exception("Daemon is already started")

        # create and switch to daemon thread
        self._daemonize()

        # run the body of the daemon
        self.run()


    def stop(self):
        # check the pidfile existing
        if os.path.exists(self._pidfile):
            # read pid from the file
            with open(self._pidfile, 'r') as f:
                pid = int(f.read().strip())

            # remove the pidfile
            os.remove(self._pidfile)

            # kill daemon
            os.kill(pid, SIGTERM)

        else:
            raise Exception("Daemon is not started")


    def restart(self):
        self.stop()
        self.start()
<逆流佳人身旁 2024-08-15 10:29:33

要创建像服务一样运行的东西,您可以使用这个东西:

您必须做的第一件事是安装 水泥框架:
Cement 框架是一个 CLI 框架,您可以在其上部署应用程序。

应用程序的命令行界面:

interface.py

 from cement.core.foundation import CementApp
 from cement.core.controller import CementBaseController, expose
 from YourApp import yourApp

 class Meta:
    label = 'base'
    description = "your application description"
    arguments = [
        (['-r' , '--run'],
          dict(action='store_true', help='Run your application')),
        (['-v', '--version'],
          dict(action='version', version="Your app version")),
        ]
        (['-s', '--stop'],
          dict(action='store_true', help="Stop your application")),
        ]

    @expose(hide=True)
    def default(self):
        if self.app.pargs.run:
            #Start to running the your app from there !
            YourApp.yourApp()
        if self.app.pargs.stop:
            #Stop your application
            YourApp.yourApp.stop()

 class App(CementApp):
       class Meta:
       label = 'Uptime'
       base_controller = 'base'
       handlers = [MyBaseController]

 with App() as app:
       app.run()

YourApp.py 类:

 import threading

 class yourApp:
     def __init__:
        self.loger = log_exception.exception_loger()
        thread = threading.Thread(target=self.start, args=())
        thread.daemon = True
        thread.start()

     def start(self):
        #Do every thing you want
        pass
     def stop(self):
        #Do some things to stop your application

请记住,您的应用程序必须在线程上运行才能成为守护进程

要运行应用程序,只需在命令行中执行此操作

python 接口.py --help

to creating some thing that is running like service you can use this thing :

The first thing that you must do is installing the Cement framework:
Cement frame work is a CLI frame work that you can deploy your application on it.

command line interface of the app :

interface.py

 from cement.core.foundation import CementApp
 from cement.core.controller import CementBaseController, expose
 from YourApp import yourApp

 class Meta:
    label = 'base'
    description = "your application description"
    arguments = [
        (['-r' , '--run'],
          dict(action='store_true', help='Run your application')),
        (['-v', '--version'],
          dict(action='version', version="Your app version")),
        ]
        (['-s', '--stop'],
          dict(action='store_true', help="Stop your application")),
        ]

    @expose(hide=True)
    def default(self):
        if self.app.pargs.run:
            #Start to running the your app from there !
            YourApp.yourApp()
        if self.app.pargs.stop:
            #Stop your application
            YourApp.yourApp.stop()

 class App(CementApp):
       class Meta:
       label = 'Uptime'
       base_controller = 'base'
       handlers = [MyBaseController]

 with App() as app:
       app.run()

YourApp.py class:

 import threading

 class yourApp:
     def __init__:
        self.loger = log_exception.exception_loger()
        thread = threading.Thread(target=self.start, args=())
        thread.daemon = True
        thread.start()

     def start(self):
        #Do every thing you want
        pass
     def stop(self):
        #Do some things to stop your application

Keep in mind that your app must run on a thread to be daemon

To run the app just do this in command line

python interface.py --help

听风念你 2024-08-15 10:29:33

使用您的系统提供的任何服务管理器 - 例如在 Ubuntu 下使用 upstart。这将为您处理所有细节,例如启动时启动、崩溃时重新启动等。

Use whatever service manager your system offers - for example under Ubuntu use upstart. This will handle all the details for you such as start on boot, restart on crash, etc.

单身狗的梦 2024-08-15 10:29:33

您可以在脚本或另一个脚本中将进程作为子进程运行,

subprocess.Popen(arguments, close_fds=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)

或者使用现成的实用程序

https://github.com/megashchik/d-handler

You can run a process as a subprocess inside a script or in another script like this

subprocess.Popen(arguments, close_fds=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)

Or use a ready-made utility

https://github.com/megashchik/d-handler

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文