ecFlow笔记:ecFlow日志解析 - 状态变化记录
本文属于介绍 NWPC 工作流日志工具的系列文章。
之前的文章《ecFlow笔记:ecFlow日志解析 - 通用字段》介绍如何解析 ecFlow 日志的通用字段。
本文介绍如何解析状态变化记录(StatusLogRecord
)类型的 ecFlow 日志条目。
本文代码均来自 nwpc-oper/nwpc-workflow-log-model 项目。
介绍
ecFlow 实现工作流的核心机制就是跟踪任务(Task)节点的状态,并定时根据状态决定工作流应采取的下一步动作。
正常情况下,ecFlow 任务的正常状态变化如下:
排队(queued)-> 提交(submitted)-> 运行(active)-> 完成(complete)
当出错时,节点会进入出错(aborted)状态。另外, 节点也可以被挂起(suspended),阻止任务运行。
节点状态的每次变化,都会在 ecFlow 日志中记录相应的条目。 容器节点(Family 和 Suite)的状态是其所有子节点的状态种类中权重最大的状态。 所以 Task 节点状态变化通常会导致一系列父节点状态改变。 表现在日志中就是有一串关联的节点状态同时改变,如下所示
MSG:[11:08:52 3.6.2020] chd:init /grapes_tym/grapes_d01/06/prods/grib2/grib2_003
LOG:[11:08:52 3.6.2020] active: /grapes_tym/grapes_d01/06/prods/grib2/grib2_003
LOG:[11:08:52 3.6.2020] active: /grapes_tym/grapes_d01/06/prods/grib2
LOG:[11:08:52 3.6.2020] active: /grapes_tym/grapes_d01/06/prods
权重列表如下,其中最后两个状态仅限于 ecFlow 服务节点。
状态 | 说明 |
---|---|
Unknown | 权重最小 |
Complete | |
Queued | |
Submitted | |
Active | |
Suspend | |
Aborted | 对于 task 是最重要的状态 |
Shutdown | 仅限于 ecFlow 服务节点 |
Halted | 最重要的状态,仅限于 ecFlow 服务节点 |
日志示例
下面举例说明各个状态的日志。
排队(queued)
通常情况下,queued 是任务的默认状态。 当系统中最后一个任务完成时,系统会自动滚动到下一天,并将所有任务的状态设为 queued。
下面示例中 /NWP_HAZE_ext_v3.2/housekeep/housekeeping
任务完成后,NWP_HAZE_ext_v3.2
系统的所有任务都已完成,ecFlow 会自动将所有的节点设置为 queued。
MSG:[23:45:04 22.5.2020] chd:complete /NWP_HAZE_ext_v3.2/housekeep/housekeeping
LOG:[23:45:04 22.5.2020] complete: /NWP_HAZE_ext_v3.2/housekeep/housekeeping
LOG:[23:45:04 22.5.2020] complete: /NWP_HAZE_ext_v3.2/housekeep
LOG:[23:45:04 22.5.2020] complete: /NWP_HAZE_ext_v3.2
LOG:[23:45:04 22.5.2020] queued: /NWP_HAZE_ext_v3.2
LOG:[23:45:04 22.5.2020] queued: /NWP_HAZE_ext_v3.2/00
LOG:[23:45:04 22.5.2020] queued: /NWP_HAZE_ext_v3.2/00/regridder
LOG:[23:45:04 22.5.2020] queued: /NWP_HAZE_ext_v3.2/00/interpf
LOG:[23:45:04 22.5.2020] queued: /NWP_HAZE_ext_v3.2/00/fcst
LOG:[23:45:04 22.5.2020] queued: /NWP_HAZE_ext_v3.2/00/fcstmonitor
提交(submitted)
提交(submitted)和运行(active)都表示任务开始运行,但具体含义不同。
submitted 表示 ecFlow 服务执行任务运行命令(由 ECF_JOB_CMD
定义),状态改变由 ecFlow 服务直接完成。但如果将作业提交到类似 Slurm 的作业调度系统,那么执行命令后,任务不一定立即运行。
所以,任务在开始运行时需要使用 ecflow_client --init
命令告诉 ecFlow 服务自己已经开始运行,也就是将节点状态变为 active。
submitted 与 active 状态的区别与关联见下图。
在 ecFlow 日志中,submitted 状态没有相关的 child 命令记录。如下所示:
LOG:[04:10:00 31.5.2020] submitted: /mosaic_v3/03/get job_size:8151
LOG:[04:10:00 31.5.2020] submitted: /mosaic_v3/03
LOG:[04:10:00 31.5.2020] submitted: /mosaic_v3
LOG:[04:10:00 31.5.2020] submitted: /
运行(active)
运行(active)表示任务已实际开始运行。日志如下所示:
MSG:[04:10:01 31.5.2020] chd:init /mosaic_v3/03/get
LOG:[04:10:01 31.5.2020] active: /mosaic_v3/03/get
LOG:[04:10:01 31.5.2020] active: /mosaic_v3/03
LOG:[04:10:01 31.5.2020] active: /mosaic_v3
LOG:[04:10:01 31.5.2020] active: /
完成(complete)
完成(complete)表示任务运行结束。
通常来自任务脚本执行的 ecflow_client --complete
命令。
MSG:[01:30:03 4.6.2020] chd:complete /env_grib_pi_v1_0/env_grib_pi/GMF_ENV/gmf/housekeep
LOG:[01:30:03 4.6.2020] complete: /env_grib_pi_v1_0/env_grib_pi/GMF_ENV/gmf/housekeep
LOG:[01:30:03 4.6.2020] complete: /env_grib_pi_v1_0/env_grib_pi/GMF_ENV/gmf
LOG:[01:30:03 4.6.2020] complete: /env_grib_pi_v1_0/env_grib_pi/GMF_ENV
也可能来自用户执行强制设为完成(force complete)操作。
MSG:[00:32:59 4.6.2020] --force=complete recursive /grapes_emer_v1_2/12_3 :nwp
LOG:[00:32:59 4.6.2020] complete: /grapes_emer_v1_2/12_3
LOG:[00:32:59 4.6.2020] complete: /grapes_emer_v1_2/12_3/typhoon
LOG:[00:32:59 4.6.2020] complete: /grapes_emer_v1_2/12_3/typhoon/tcreport_get
或者节点的默认状态就是 complete,在系统进入下一天的循环时,会自动将该节点设置为 complete 状态。
LOG:[02:01:47 3.6.2020] queued: /meso_post/06/meso_chartos/rundir_area_3h/area_grapes_meso_conv_prep_v2/area_grapes_meso_conv_prep_v2_sep_030
LOG:[02:01:47 3.6.2020] queued: /meso_post/06/meso_chartos/rundir_area_6h
LOG:[02:01:47 3.6.2020] complete: /meso_post/06/meso_chartos/rundir_area_6h
LOG:[02:01:47 3.6.2020] queued: /meso_post/06/meso_chartos/housekeep_chartos
出错(aborted)
出错(aborted)状态表示任务运行出错,需要运维人员额外关注,在 ecflow_ui 界面中会弹出提示窗口。
通常情况下,aborted 状态由任务脚本执行 ecflow_client --aborted [+reason]
命令而触发。
日志会记录任务的运行序号和出错的原因。NWPC 业务系统脚本中出错原因均设为 trap
。
MSG:[05:20:57 19.5.2020] chd:abort /meso_post/03/uploadAll/upload_chartos/3h/prep_3hr/upload_prep_3hr_020 trap
LOG:[05:20:57 19.5.2020] aborted: /meso_post/03/uploadAll/upload_chartos/3h/prep_3hr/upload_prep_3hr_020 try-no: 1 reason: trap
LOG:[05:20:57 19.5.2020] aborted: /meso_post/03/uploadAll/upload_chartos/3h/prep_3hr
LOG:[05:20:57 19.5.2020] aborted: /meso_post/03/uploadAll/upload_chartos/3h
LOG:[05:20:57 19.5.2020] aborted: /meso_post/03/uploadAll/upload_chartos
LOG:[05:20:57 19.5.2020] aborted: /meso_post/03/uploadAll
LOG:[05:20:57 19.5.2020] aborted: /meso_post/03
LOG:[05:20:57 19.5.2020] aborted: /meso_post
LOG:[05:20:57 19.5.2020] aborted: /
也可能来自用户执行的 kill
命令。
MSG:[00:20:26 29.5.2020] --kill /grapes_tym_post/18/data/000/shanxi :nwp_pd
MSG:[00:20:26 29.5.2020] --force=aborted /grapes_tym_post/18/data/000/shanxi :nwp_pd
LOG:[00:20:26 29.5.2020] aborted: /grapes_tym_post/18/data/000/shanxi try-no: 1 reason:
或者来自用户执行强制设置 aborted 状态的操作
MSG:[01:30:52 12.6.2020] --force=aborted /grapes_tym_post/18/data/000/shanxi :nwp_pd
LOG:[01:30:52 12.6.2020] aborted: /grapes_tym_post/18/data/000/shanxi try-no: 2 reason:
LOG:[01:30:52 12.6.2020] aborted: /grapes_tym_post/18/data/000
LOG:[01:30:52 12.6.2020] aborted: /grapes_tym_post/18/data
LOG:[01:30:52 12.6.2020] aborted: /grapes_tym_post/18
LOG:[01:30:52 12.6.2020] aborted: /grapes_tym_post
LOG:[01:30:52 12.6.2020] aborted: /
挂起(suspended)
挂起(suspended)状态用于阻止任务执行。
不过笔者发现日志中仅有 --suspend
命令的记录,而没有 suspended 状态的条目,暂不给出示例。
结构
状态变化记录(StatusLogRecord)的结构继承自通用日志结构(EcflowLogRecord),
将 Event
字段设置为状态变化 EventType.Status
。
同时增加状态(Status)字段,记录变化后的状态。
对于不同的状态,在附加信息(Additional Information)字段中会记录额外的信息,例如:submitted 状态记录作业脚本大小,aborted 状态记录出错原因。
解析
在经过通用解析后,将 command 字段设置为状态字段(Status)。 并根据状态值进行相应的解析。
对于 queued,active 和 complete 三种状态,仅需解析节点路径。
对于 aborted 和 submitted 两种状态,在解析节点路径基础上,还需解析额外信息。
其他情况的条目直接被忽略。
实现
请参考 nwpc-workflow-log-model 项目的 StatusLogRecord
类的 parse_record 函数
以下代码来自该函数,其中 self
表示 EcflowLogParser
类,line
是解析过通用字段后剩余的日志条目字符串。即
complete: /env_grib_pi_v1_0/env_grib_pi/GMF_ENV/gmf/housekeep
获取状态
查找 :
,获取状态
start_pos = 0
end_pos = status_line.find(":", start_pos)
event = status_line[start_pos:end_pos]
self.event = event
self.status = NodeStatus[event]
获取节点路径
查找 " "
,获取节点路径
start_pos = end_pos + 2
end_pos = status_line.find(" ", start_pos)
self.node_path = status_line[start_pos:].strip()
获取附加信息
如果 event == "aborted"
self.additional_attrs["reason"] = status_line[end_pos + 1:]
如果 event == "submitted"
if end_pos == -1:
self.node_path = status_line[start_pos:]
else:
self.node_path = status_line[start_pos:end_pos]
start_pos = end_pos + 1
end_pos = status_line.find(":", start_pos)
参考
ecFlow 官方文档:
Status of a suite,family or server
项目: