P S*_*ved 93
你有两个选择.
做一个调用脚本的正确的cron作业.Cron是GNU/Linux守护程序的通用名称,它根据您设置的计划定期启动脚本.将脚本添加到crontab中或将符号链接放入特殊目录中,守护程序处理在后台启动它的作业.您可以在维基百科阅读更多内容.有各种不同的cron守护进程,但你的GNU/Linux系统应该已经安装了它.
使用某种python方法(例如一个库)让你的脚本能够守护自己.是的,它需要一个简单的事件循环(你的事件是定时器触发,可能由睡眠功能提供).
我不建议你选择2.,因为你实际上是在重复cron功能.Linux系统范例是让多个简单工具交互并解决您的问题.除非您有其他原因要制作守护程序(除了定期触发),否则请选择其他方法.
此外,如果您使用daemonize循环并且发生崩溃,那么没有人会在此之后检查邮件(正如Ivan Nevostruev在对此答案的评论中所指出的那样).如果脚本作为cron作业添加,它将再次触发.
the*_*row 71
这是一个很好的课程,取自这里:
#!/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().
"""
Run Code Online (Sandbox Code Playgroud)
Pro*_*ody 57
你应该使用python-daemon库,它会处理所有事情.
从PyPI:Library实现一个表现良好的Unix守护进程.
jhw*_*ist 38
您可以使用fork()从tty中分离脚本并让它继续运行,如下所示:
import os, sys
fpid = os.fork()
if fpid!=0:
# Running as daemon now. PID is fpid
sys.exit(0)
Run Code Online (Sandbox Code Playgroud)
当然你还需要实现无限循环,比如
while 1:
do_your_check()
sleep(5)
Run Code Online (Sandbox Code Playgroud)
希望这是你的开始.
Hei*_*tro 22
假设您真的希望您的循环作为后台服务 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
Run Code Online (Sandbox Code Playgroud)
将该文件放在您的守护程序服务文件夹(通常是/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>
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用以下命令检查您的服务是否正在运行:
systemctl | grep running
Run Code Online (Sandbox Code Playgroud)
Kis*_*e K 14
您还可以使用shell脚本将python脚本作为服务运行.首先创建一个shell脚本来运行这样的python脚本(scriptname仲裁名称)
#!/bin/sh
script='/home/.. full path to script'
/usr/bin/python $script &
Run Code Online (Sandbox Code Playgroud)
现在在/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
Run Code Online (Sandbox Code Playgroud)
现在,您可以使用命令/etc/init.d/scriptname start或stop启动和停止python脚本.
Chr*_*son 12
cron显然是很多目的的绝佳选择.但是,它不会像您在OP中请求的那样创建服务或守护程序. cron只是定期运行工作(意味着工作开始和停止),并且不会超过一次/分钟.存在一些问题cron- 例如,如果您的脚本的先前实例在下次cron计划到来并且启动新实例时仍在运行,那可以吗? cron不处理依赖; 它只是试图在时间表说到的时候开始工作.
如果您发现一个真正需要守护进程的情况(一个永不停止运行的进程),请查看supervisord.它提供了一种简单的方法来包装正常的非守护程序脚本或程序,并使其像守护程序一样运行.这是一种比创建本机Python守护进程更好的方法.
fcm*_*fcm 10
一个简单且受支持的版本是Deamonize从Python Package Index(PyPI)安装它:
$ pip install daemonize
Run Code Online (Sandbox Code Playgroud)
然后使用像:
...
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()
Run Code Online (Sandbox Code Playgroud)
如果您正在使用终端(ssh 或其他东西),并且希望在从终端注销后保持脚本长时间工作,您可以尝试以下操作:
screen
apt-get install screen
在里面创建一个虚拟终端(即 abc): screen -dmS abc
现在我们连接到 abc: screen -r abc
所以,现在我们可以运行 python 脚本了: python keep_sending_mails.py
从现在开始,您可以直接关闭终端,但是,python 脚本将继续运行而不是被关闭
由于 this
keep_sending_mails.py的 PID 是虚拟屏幕的子进程而不是终端(ssh)
如果你想回去检查你的脚本运行状态,你可以screen -r abc再次使用
Ubuntu 有一种非常简单的方法来管理服务。对于python,不同之处在于所有依赖项(包)必须位于运行主文件的同一目录中。
我只是设法创建这样的服务来向我的客户提供天气信息。脚步:
像往常一样创建您的 Python 应用程序项目。
在本地安装所有依赖项,例如: sudo pip3 install package_name -t 。
创建命令行变量并在代码中处理它们(如果需要)
创建服务文件。一些(极简主义)像:
[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
Run Code Online (Sandbox Code Playgroud)
将文件另存为 myweather.service(例如)
如果在当前目录中启动,请确保您的应用程序运行
python3 main.py httpport=9570 provider=OWMap
Run Code Online (Sandbox Code Playgroud)
上面生成的名为 myweather.service 的服务文件(扩展名为 .service 很重要)将被系统视为您的服务的名称。这是您将用于与服务交互的名称。
复制服务文件:
sudo cp myweather.service /lib/systemd/system/myweather.service
Run Code Online (Sandbox Code Playgroud)
刷新恶魔注册表:
sudo systemctl daemon-reload
Run Code Online (Sandbox Code Playgroud)
停止服务(如果它正在运行)
sudo service myweatherr stop
Run Code Online (Sandbox Code Playgroud)
启动服务:
sudo service myweather start
Run Code Online (Sandbox Code Playgroud)
检查状态(带有打印语句所在位置的日志文件):
tail -f /var/log/syslog
Run Code Online (Sandbox Code Playgroud)
或检查状态:
sudo service myweather status
Run Code Online (Sandbox Code Playgroud)
如果需要,重新开始进行另一次迭代
此服务现在正在运行,即使您注销也不会受到影响。如果主机关闭并重新启动,则是,此服务将重新启动...我的移动 android 应用程序的信息...