nova中定时任务(periodic_task)原理分析
来源:互联网 发布:黑马程序员视频百度云 编辑:程序博客网 时间:2024/06/06 09:28
原文地址
https://github.com/stanzgy/wiki/blob/master/openstack/inside-nova-periodic-task.md#nova%E4%B8%AD%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1periodic_task%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90
nova中定时任务(periodic_task)原理分析
在nova源代码中, 可以在很多函数上看到@periodic_task
这样的修饰符, 我们知道这是nova的定时任务,可以让这个函数周期性执行, 但是可能不太了解这个修饰符产生作用的原理和用法, 这里将详细说明一下.
decorator nova.manager.periodic_task
# in nova.manager def periodic_task(*args, **kwargs): def decorator(f): f._periodic_task = True f._ticks_between_runs = kwargs.pop('ticks_between_runs', 0) return f if kwargs: return decorator else: return decorator(args[0])可以看到
@periodic_task
其实只是给被修饰的函数加上了_periodic_task
和_ticks_between_runs
2个attr, 并没有做其他的操作. 周期执行函数的action实际上是nova.manager.Manager
和nova.utils.LoopingCall
配合实现的, 后面将详细说明.
black magic of nova.manager.ManagerMeta
# in nova.manager class ManagerMeta(type): def __init__(cls, names, bases, dict_): super(ManagerMeta, cls).__init__(names, bases, dict_) try: cls._periodic_tasks = cls._periodic_tasks[:] except AttributeError: cls._periodic_tasks = [] try: cls._ticks_to_skip = cls._ticks_to_skip.copy() except AttributeError: cls._ticks_to_skip = {} for value in cls.__dict__.values(): if getattr(value, '_periodic_task', False): task = value name = task.__name__ cls._periodic_tasks.append((name, task)) cls._ticks_to_skip[name] = task._ticks_between_runsnova.manager中的
ManagerMeta
类是nova.manager.Manager
的metaclass(在后面可以看到), 这里可以简单的认为ManagerMeta
是Manager
的父类. 在nova.manager.Manager
初始化时, 会调用ManagerMeta
的__init__()
方法.(metaclass属于python里的黑魔法内容, 这里不做详细说明, 大法师们感兴趣可以去看看官方手册http://docs.python.org/reference/datamodel.html#customizing-class-creation)
for value in cls.__dict__.values(): if getattr(value, '_periodic_task', False):
ManagerMeta.__init__()
中的这两行会将cls(也就是Manager
对象自己, 注意是Manager对象 不是Manager
的实例)中所有使用过@periodic_task
修饰符修饰的函数对象 过滤出来.过滤后会将这些函数对象放入Manager._periodic_tasks
中, 后面定时任务的实现都是从这个变量里取出函数对象并执行.
nova.manager.Manager.periodic_tasks
(注意和nova.manager.periodic_task
的区别)class Manager(base.Base): __metaclass__ = ManagerMeta def periodic_tasks(self, context, raise_on_error=False): for task_name, task in self._periodic_tasks: full_task_name = '.'.join([self.__class__.__name__, task_name]) ticks_to_skip = self._ticks_to_skip[task_name] if ticks_to_skip > 0: LOG.debug(_("Skipping %(full_task_name)s, %(ticks_to_skip)s" " ticks left until next run"), locals()) self._ticks_to_skip[task_name] -= 1 continue self._ticks_to_skip[task_name] = task._ticks_between_runs LOG.debug(_("Running periodic task %(full_task_name)s"), locals()) try: task(self, context) except Exception as e: if raise_on_error: raise LOG.exception(_("Error during %(full_task_name)s: %(e)s"), locals())从前面
ManagerMeta
的说明我们已经知道Manager
对象建立时, 会将所有attr_periodic_task
为True 的函数对象放入self._periodic_tasks
中.在Manager
中, 我们可以发现一个和periodic_task
十分相似的函数periodic_tasks
, 通过阅读函数代码可以发现这个函数实际上的作用就是把所有在self._periodic_tasks
中的函数对象(也就是所有用@periodic_task
修饰符修饰过的函数)全部遍历并调用一遍. 如果能定期调用这个函数的话, 就能实现类似linux中crontab的定时任务功能.
下面将说明nova如何定时调用nova.manager.Manager.periodic_tasks
实现定时任务.
nova.utils.LoopingCall
class LoopingCall(object): def __init__(self, f=None, *args, **kw): self.args = args self.kw = kw self.f = f self._running = False def start(self, interval, now=True): self._running = True done = event.Event() def _inner(): if not now: greenthread.sleep(interval) try: while self._running: self.f(*self.args, **self.kw) if not self._running: break greenthread.sleep(interval) except LoopingCallDone, e: self.stop() done.send(e.retvalue) except Exception: LOG.exception(_('in looping call')) done.send_exception(*sys.exc_info()) return else: done.send(True) self.done = done greenthread.spawn(_inner) return self.done def stop(self): self._running = False def wait(self): return self.done.wait()
nova.utils.LoopingCall
的作用就是实现前面提到的定时调用函数的功能.
将函数对象作为LoopingCall
的第一个构造参数传入构造一个LoopingCall
对象, 然后调用其start()
方法后调用其wait()
方法, 就可以实现定时执行函数的功能.
start
方法的interval
参数为函数两次执行期间的时间间隔, 单位为秒. 前面提到的@periodic_task
修饰符可以设置一个参数ticks_between_runs
, 是与其配合使用的, 指经过几次ticks才执行函数. 比如, 上下文为@periodic_task(ticks_between_runs=2)
并且interval=5
的话, 被修饰的函数将每 (2+1)*5=15 seconds 执行一次
如果被修饰的函数里raise nova.utils.LoopingCallDone
, 可以让LoopingCall的定时任务close gracefully.
- nova中定时任务(periodic_task)原理分析
- 通过periodic_task.periodic_task 实现周期性任务的原理
- nova中通过FixedIntervalLoopingCall实现的定时任务
- OpenStack之Nova分析——Nova Compute定时任务(一)
- OpenStack之Nova分析——Nova Compute定时任务(二)
- OpenStack之Nova分析——Nova Compute定时任务(三)
- @periodic_task简述及nova资源刷新机制
- Quartz定时任务执行原理分析
- Java Timer 定时任务实现原理及缺陷分析
- Java Timer 定时任务实现原理及缺陷分析
- Sqlserver中定时任务
- Android中定时任务
- java 中定时任务
- Golang Cron 定时任务分析
- Android后台定时任务分析
- Spring定时任务源码分析
- Oracle中实现定时任务
- 数据库中创建定时任务
- 利用.bat脚本使得可运行jar开机自动运行
- UML用例图
- struts action json 示例
- AndroidManifest.xml详解
- JSON 语法
- nova中定时任务(periodic_task)原理分析
- 程序减肥,strip,eu-strip 及其符号表
- Palindrome Partitioning
- 黑马程序员--10.网络编程--03.【UDP协议相关类】【DatagramPacket类】【DatagramSocket类】【UDP发送端和接收端】
- JVM out of memory error
- LeetCode - Sudoku Solver
- 重装windows后easybcd修复ubuntu启动项
- 在2013 美国计算器图形学年会(SigGraph 2013)上, WebGL成主角
- vs2008编译 wince慢的解决方案