gpt4 book ai didi

python - 当使用 cron 管理程序时,从 cron 作业运行脚本的行为与使用 django manage.py 从命令行运行时的行为不同

转载 作者:行者123 更新时间:2023-12-01 09:04:25 24 4
gpt4 key购买 nike

我知道 crons 在与命令行不同的环境中运行,但我到处都使用绝对路径,而且我不明白为什么我的脚本行为不同。我相信它在某种程度上与我的 cron_supervisor 有关,它在子进程中运行 django“manage.py”。

定时任务:

0 * * * * /home/p1/.virtualenvs/prod/bin/python /home/p1/p1/manage.py cron_supervisor --command="/home/p1/.virtualenvs/prod/bin/python /home/p1/p1/manage.py envoyer_argent"

这将调用 cron_supervisor,并调用脚本,但脚本不会像我运行时那样执行:

/home/p1/.virtualenvs/prod/bin/python /home/p1/p1/manage.py envoyer_argent

当通过另一个脚本运行该脚本时,为了正确调用该脚本,是否需要做一些特殊的事情?

这里是主管,它基本上用于错误处理并确保我们在 cron 脚本本身出现问题时收到警告。

import logging
import os
from subprocess import PIPE, Popen

from django.core.management.base import BaseCommand

from command_utils import email_admin_error, isomorphic_logging
from utils.send_slack_message import send_slack_message

CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_DIR = CURRENT_DIR + '/../../../'

logging.basicConfig(
level=logging.INFO,
filename=PROJECT_DIR + 'cron-supervisor.log',
format='%(asctime)s %(levelname)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)


class Command(BaseCommand):
help = "Control a subprocess"

def add_arguments(self, parser):
parser.add_argument(
'--command',
dest='command',
help="Command to execute",
)
parser.add_argument(
'--mute_on_success',
dest='mute_on_success',
action='store_true',
help="Don't post any massage on success",
)

def handle(self, *args, **options):
try:
isomorphic_logging(logging, "Starting cron supervisor with command \"" + options['command'] + "\"")
if options['command']:
self.command = options['command']
else:
error_message = "Empty required parameter --command"
# log error
isomorphic_logging(logging, error_message, "error")
# send slack message
send_slack_message("Cron Supervisor Error: " + error_message)
# send email to admin
email_admin_error("Cron Supervisor Error", error_message)
raise ValueError(error_message)

if options['mute_on_success']:
self.mute_on_success = True
else:
self.mute_on_success = False

# running process
process = Popen([self.command], stdout=PIPE, stderr=PIPE, shell=True)
output, error = process.communicate()

if output:
isomorphic_logging(logging, "Output from cron:" + output)

# check for any subprocess error
if process.returncode != 0:
error_message = 'Command \"{command}\" - Error \nReturn code: {code}\n```{error}```'.format(
code=process.returncode,
error=error,
command=self.command,
)
self.handle_error(error_message)

else:
message = "Command \"{command}\" ended without error".format(command=self.command)
isomorphic_logging(logging, message)
# post message on slack if process isn't muted_on_success
if not self.mute_on_success:
send_slack_message(message)
except Exception as e:
error_message = 'Command \"{command}\" - Error \n```{error}```'.format(
error=e,
command=self.command,
)
self.handle_error(error_message)

def handle_error(self, error_message):
# log the error in local file
isomorphic_logging(logging, error_message)
# post message in slack
send_slack_message(error_message)
# email admin
email_admin_error("Cron Supervisor Error", error_message)

通过 cron_supervisor 被 cron 调用时脚本未正确执行的示例:

# -*- coding: utf-8 -*-

import json
import logging
import os

from django.conf import settings
from django.core.management.base import BaseCommand

from utils.lock import handle_lock

logging.basicConfig(
level=logging.INFO,
filename=os.path.join(settings.BASE_DIR, 'crons.log'),
format='%(asctime)s %(levelname)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
class Command(BaseCommand):
help = "Envoi de l'argent en attente"

@handle_lock
def handle(self, *args, **options):

logging.info("some logs that won't be log (not called)")

logging.info("Those logs will be correcly logged")

此外,我还有一个关于日志记录的问题,我也不太明白,我指定将日志存储在 cron-supervisor.log 中,但它们不会存储在那里,我无法不明白为什么。 (但这与我的主要问题无关,只是对调试没有帮助)

最佳答案

你的cron作业不能只在virtualenv中运行Python解释器;这是完全不够的。您需要像在交互式环境中一样激活环境。

0 * * * * . /home/p1/.virtualenvs/prod/bin/activate; python /home/p1/p1/manage.py cron_supervisor --command="python /home/p1/p1/manage.py envoyer_argent"

这已经足够复杂,您可能需要创建一个包含这些命令的单独的包装器脚本。

如果没有正确诊断当前脚本如何无法工作,则完全有可能仅此修复是不够的。 Cron 作业不仅(或特别)需要绝对路径;与交互式 shell 相比,主要区别在于 cron 作业在不同且更空闲的环境中运行,例如shell 的 PATH、各种库路径、环境变量等可能不同或完全缺失;当然,没有互动设施。

系统变量有望由您的 virtualenv 处理;如果正确完成,激活它将设置脚本所需的所有变量(PATHPYTHONPATH 等)。仍然可能存在诸如区域设置之类的内容,这些内容仅在您以交互方式登录时才由您的 shell 设置;但同样,没有详细信息,我们只是希望这对您来说不是问题。

有些人推荐绝对路径的原因是,无论您的工作目录如何,这都可以工作。但正确编写的脚本应该在任何目录中都能正常工作;如果重要的话,cron 作业将在所有者的主目录中启动。如果您想从那里指向相对路径,这将在 cron 作业内正常工作,就像在外部一样。

顺便说一句,如果 subprocess 模块中的较高级别包装器之一执行您想要的操作,您可能不应该使用 subprocess.Popen()。除非与旧版 Python 版本的兼容性很重要,否则您可能应该使用 subprocess.run() ...尽管将 Python 作为 Python 的子进程运行通常也是一种无用的麻烦。另请参阅我对 this related question. 的回答

关于python - 当使用 cron 管理程序时,从 cron 作业运行脚本的行为与使用 django manage.py 从命令行运行时的行为不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52187208/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com