ecFlow笔记:定时任务没有启动 - 分析

目录

上一篇文章《ecFlow笔记:定时任务没有启动 - 排查》中推测定时任务没有启动的原因是因为作业生成超时,并提到该推测成立需要下面两个必要条件:

  • ecFlow 中作业生成和检查依赖关系等操作是串行的
  • ecFlow 检查时间依赖不是 >=,即超过时间点的任务不会被启动

本文逐条分析以上两个条件,为上一篇文章的推测提供依据。

串行处理

ecFlow 服务端使用 Boost::Asio 实现事件响应,而 Boost::Asio 即支持单线程也支持多线程。

源码中使用 ECFLOW_MT 宏定义是否使用多线程模式,在 Server\src\Server.hpp 中有下面的代码

// ECFLOW_MT See doc/multi-threaded-server.tar/ddoc
//#define ECFLOW_MT 1
#ifdef ECFLOW_MT
#include "CConnection.hpp" // Must come before boost/serialisation headers.
#else
#include "Connection.hpp"  // Must come before boost/serialisation headers.
#include "ClientToServerRequest.hpp"
#include "ServerToClientResponse.hpp"
#endif

说明默认情况下,ECFLOW_MT 未定义,使用单线程模式。

在 Server\src\ServerOptions.cpp 中可以看到,如果定义了 ECFLOW_MTecflow_server 命令会有 threads 参数。

在 CMA-PI 上运行 ecflow_server -h,列出的参数中没有 threads,说明我们使用的 ecFlow 是单线程模式。

在 Server\src\NodeTreeTraverser.cpp 中有下面的函数

void NodeTreeTraverser::start_timer()
{
	/// Appears that expires_from_now is more accurate then expires_at i.e timer_.expires_at( timer_.expires_at() + boost::posix_time::seconds( poll_at ) );
	timer_.expires_from_now(  boost::posix_time::seconds( 1 ) );
#ifdef ECFLOW_MT
	timer_.async_wait( server_->strand_.wrap( boost::bind( &NodeTreeTraverser::traverse,this,boost::asio::placeholders::error ) ) );
#else
	timer_.async_wait( server_->io_service_.wrap( boost::bind( &NodeTreeTraverser::traverse,this,boost::asio::placeholders::error ) ) );
#endif
}

在单线程模式中,使用 io_service_ 执行 NodeTreeTraverser::traverse 函数。io_service_boost::asio::io_service 对象,同时只能运行一个函数,也就是 NodeTreeTraverser::traverse 函数是串行执行的。

tranverse 函数经过层层调用,会执行下面的函数

void NodeTreeTraverser::traverse_node_tree_and_job_generate(
		const boost::posix_time::ptime& start_time,
		bool user_cmd_context) const
{
    // ...
}

即检查触发器,提交满足依赖关系的作业,也就是作业生成和检查依赖关系等操作是串行的。

时间依赖

时间依赖属性由 TimeAttr 类定义,其中包含保存时间设置的 TimeSeries 对象。

TimeSeriesTimeSeries::match_duration_with_time_series 函数中有下面的语句(省略部分注释):

if ( hours ==  nextTimeSlot_td.hours() && minutes == nextTimeSlot_td.minutes()) 
{
    return true;
}

也就说明时间依赖检测用的是 ==,超时后只能等待第二天的同一时刻才会满足触发条件。

另外 ANode\src\Jobs.hpp 中有下面的注释内容:

Job submission MUST be done sequentially,as each job submission could consume a resource(i.e like a limit), which can affect subsequent jobs.

The process of resolving dependencies and submitting all the tasks, must take less than 60 seconds. As this is resolution of the clock.

明确指出作业提交是串行的,并且单次检查依赖关系并提交所有作业的总时间不能超过 60 秒。

总结

虽然上述分析不够严谨,笔者也没有仔细检查所有的源代码,但笔者认为如果作业生成时间超过 60 秒,可能会出现未知的问题。 而 5 月 12 日出现的 time 依赖失效的现象很可能就属于这类未知的问题。

当然,本文仅代表作者个人观点,具体原因有待进一步查明,所用数据无法代表真实情况,严禁转载。 关于 CMA-PI 的相关信息,请以官方发布的信息及经过同行评议的论文为准。