首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >作业计划- YAML用于编写作业定义?

作业计划- YAML用于编写作业定义?
EN

Stack Overflow用户
提问于 2018-03-05 17:22:58
回答 2查看 1.2K关注 0票数 4

在我们的遗留作业调度软件(构建在crontab之上)中,我们使用apache格式(解析器)来编写作业定义,并且使用perl通用来解析配置文件。该软件具有高度定制的功能,例如在检查是否满足该命令的依赖关系后,在我的工作中运行命令,在命令失败时重新安排作业,支持自定义通知等等。

我们现在计划用python重写这个软件,并考虑像YAML这样的选项,而不是apache来编写作业定义。YAML适合编写这样的动态配置吗?

作业定义示例(每天凌晨2点运行此作业,检查是否是星期二而不是印度的假日,如果是的,请预订我的航班并发送通知):

代码语言:javascript
复制
// python function to check if it is tuesday
checkIfTuesdayAndNotHoliday()

<job> 
    calendar: indian

        <dependency: arbitrary_python_code: checkIfTuesdayAndNotHoliday()>
        <command>  
            check availability of flight
        </command>

        <success: notify: email: agrawall/>
        <failure: notify: email: ops>
        <command>
            some command to book my flight
        </command>
</job>

<crontab> 0 2 * * * </crontab>

我很难理解应该使用什么格式来定义作业(YAML、Apache、XML、JSON等)。请注意,此作业定义将在我的python脚本中转换为作业对象。

Apache配置解析器在perl中,我们目前使用的是https://metacpan.org/source/TLINDEN/Config-General-2.63/General.pm#L769

Apache解析器在python中我们计划使用https://github.com/etingof/apacheconfig

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-07-20 22:49:07

基于Python的配置文件至少以Python1.6中distutilssetup.py的形式存在(即在2000年之前)。使用这种格式的主要缺点是很难以编程方式更新配置中的值。即使您只是想做一些分析这些文件的附加实用程序,您甚至必须特别注意,您可以在不执行代码的情况下导入这样的配置文件,但也不必通过导入引入所有类型的依赖项。这可以通过使用if __name__ == '__main__':来实现,或者更容易地通过将配置信息作为文件中的数据结构来实现。

因此,如果更新文件永远不会成为一个问题,那么您将使用基于Python的数据结构,并且这些结构非常可读性。

XML和JSON不是手工编辑的好格式。XML必须有许多<>可以轻松地在没有特殊工具的情况下输入。JSON有如此多的双引号,以至于很难读懂,但它也存在各种问题,因为JSON不允许在数组和对象中尾随逗号,从而导致人们编写如下所示的对象:

代码语言:javascript
复制
{ 
    "a": 1
  , "b": 2
}

这防止您删除最后一行并忘记删除分隔键/值对的逗号,但IMO可读性不同。

另一方面,YAML可以写得非常可读的,但是在编辑文件时必须考虑到一些规则。在我的回答这里中,我展示了一些可以包含在YAML文件中的基本规则,编辑器在编辑时需要考虑这些规则。YAML可以被Python以外的其他语言读取(使用基于Python的配置文件很难)。

您可以使用YAML标记(以及与这些标记关联的适当Python对象),因此不必依赖于从某些键值对中解释键来理解该值所解释的内容:

代码语言:javascript
复制
- !Job
  calendar: !Calendar indian
  dependency: !Arbitrary_python_code checkIfTuesdayAndNotHoliday()
  command: !CommandTester
     exec: !Exec check availability of flight
     success: !Commands
       - !Notify 
          email: agrawall
       - !Exec some command to book my flight
     failure: !Commands
       - !Notify 
           email: ops

(底部是与这些标记关联的类的部分示例实现)

当您使用ruamel.yaml (免责声明:我是该包的作者)时,即使在不丢失注释、键排序、标签的情况下,YAML也可以编程更新。

我一直在参数化我的package(我管理着超过100个包,其中一些包在PyPI上,另一些包仅用于特定的客户端),通过从包的每个__init__.py文件中读取我的通用__init__.py的配置参数已经有相当长的时间了。我已经尝试过插入Python的JSON子集,但最终开发了 (Python ),它可以由setup.py轻松地解析,而无需在Python标准库中包含的AST literal_eval上导入带有一个小(100行)扩展名的__init__.py文件。

PON可以在没有任何库的情况下使用(因为它是Python数据结构的子集,包括dict、list、set、tuple和基本类型,如整数、浮点数、布尔值、字符串、日期、日期时间。因为它基于AST评估器,所以您可以在配置文件中进行计算( secs_per_day = 24 * 60 * 60)和其他评估。

PON自述文件还更详细地描述了该格式相对于YAML、JSON、INI、XML的优缺点。

PON包不需要使用配置数据,只有当您想对PON数据执行编程往返(加载编辑转储)时,才需要PON包。

代码语言:javascript
复制
import sys
from ruamel.yaml import YAML, yaml_object

yaml = YAML()

@yaml_object(yaml)
class CommandTester:
    yaml_tag = u'!CommandTester'

    def __init__(self, exec=None, success=None, failure=None):
        self.exec = exec
        self.success = success
        self.failure = failure

    def __call__(self):
        if self.exec():
            self.success()
        else:
            self.failure()

@yaml_object(yaml)
class Commands:
    """a list of commands"""
    yaml_tag = u'!Commands'

    def __init__(self, commands):
        self._commands = commands  # list of commands to execute

    @classmethod
    def from_yaml(cls, constructor, node):
        for m in yaml.constructor.construct_yaml_seq(node):
            pass
        return cls(m)

    @classmethod
    def to_yaml(cls, representer, node):
        return representer.represent_sequence(cls.yaml_tag, node._commands)

    def __call__(self, verbose=0, stop_on_error=False):
        res = True
        for cmd in self._cmd:
            try:
                res = subprocess.check_output(cmd)
            except Exception as e:
                res = False
                if stop_on_error:
                    break
            return res

@yaml_object(yaml)
class Command(Commands):
    """a single command"""
    yaml_tag = u'!Exec'

    def __init__(self, command):
        Commands.__init__(self, [command])

    @classmethod
    def from_yaml(cls, constructor, node):
        return cls(node.value)

    @classmethod
    def to_yaml(cls, representer, node):
        return representer.represent_scalar(cls.yaml_tag, node._commands[0])


@yaml_object(yaml)
class Notifier:
    yaml_tag = u'!Notify'

with open("job.yaml") as fp:
    job = yaml.load(fp)

yaml.dump(job, sys.stdout)
票数 2
EN

Stack Overflow用户

发布于 2018-07-20 20:59:24

新的趋势是使用Python文件作为配置。这就是在Django和烧瓶中所做的事情。它是人类可读的,易于定义和更新,当然,转换成Python对象也很简单。

还请参见对“不同配置格式的利弊?”的公认答案。

也请参阅本文“Python中的配置文件”

下面是一个示例(setting.py):

代码语言:javascript
复制
def check_if_tuesday_and_not_holiday():
    """check if it is tuesday and not holiday"""
    return True

JOB = {
    'calendar': 'indian',
    'dependency': {
        'arbitrary_python_code': check_if_tuesday_and_not_holiday  # callback
    },
    'command': 'check availability of flight',
    'success': {
        'notify': {
            'email': 'agrawall'
        },
        'command': 'some command to book my flight'
    },
    'failure': {
        'notify': {
            'email': 'ops'
        }
    }
}

CRONTAB = '0 2 * * *'

注意:我不确定是否理解您的配置文件,所以我尽力使它适应Python.

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49116113

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档