在我们的遗留作业调度软件(构建在crontab之上)中,我们使用apache格式(解析器)来编写作业定义,并且使用perl通用来解析配置文件。该软件具有高度定制的功能,例如在检查是否满足该命令的依赖关系后,在我的工作中运行命令,在命令失败时重新安排作业,支持自定义通知等等。
我们现在计划用python重写这个软件,并考虑像YAML这样的选项,而不是apache来编写作业定义。YAML适合编写这样的动态配置吗?
作业定义示例(每天凌晨2点运行此作业,检查是否是星期二而不是印度的假日,如果是的,请预订我的航班并发送通知):
// 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
发布于 2018-07-20 22:49:07
基于Python的配置文件至少以Python1.6中distutils‘setup.py的形式存在(即在2000年之前)。使用这种格式的主要缺点是很难以编程方式更新配置中的值。即使您只是想做一些分析这些文件的附加实用程序,您甚至必须特别注意,您可以在不执行代码的情况下导入这样的配置文件,但也不必通过导入引入所有类型的依赖项。这可以通过使用if __name__ == '__main__':来实现,或者更容易地通过将配置信息作为文件中的数据结构来实现。
因此,如果更新文件永远不会成为一个问题,那么您将使用基于Python的数据结构,并且这些结构非常可读性。
XML和JSON不是手工编辑的好格式。XML必须有许多<和>可以轻松地在没有特殊工具的情况下输入。JSON有如此多的双引号,以至于很难读懂,但它也存在各种问题,因为JSON不允许在数组和对象中尾随逗号,从而导致人们编写如下所示的对象:
{
"a": 1
, "b": 2
}这防止您删除最后一行并忘记删除分隔键/值对的逗号,但IMO可读性不同。
另一方面,YAML可以写得非常可读的,但是在编辑文件时必须考虑到一些规则。在我的回答这里中,我展示了一些可以包含在YAML文件中的基本规则,编辑器在编辑时需要考虑这些规则。YAML可以被Python以外的其他语言读取(使用基于Python的配置文件很难)。
您可以使用YAML标记(以及与这些标记关联的适当Python对象),因此不必依赖于从某些键值对中解释键来理解该值所解释的内容:
- !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包。
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)发布于 2018-07-20 20:59:24
新的趋势是使用Python文件作为配置。这就是在Django和烧瓶中所做的事情。它是人类可读的,易于定义和更新,当然,转换成Python对象也很简单。
还请参见对“不同配置格式的利弊?”的公认答案。
也请参阅本文“Python中的配置文件”。
下面是一个示例(setting.py):
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.
https://stackoverflow.com/questions/49116113
复制相似问题