顾名思义,这个类用于执行worker上需要执行的各种命令,是worker中最核心的功能。先看它的定义:
CommandExecutor中有四个变量:
cli:用于在本计算机上执行cli命令。
listener:用于将命令执行的结果和日志上传至manager,以便于查看任务的执行情况。
timeService:时间服务。
registry:保存每种任务和它们需要执行的函数的映射,比如blender-render类型的任务就需要执行计算机上的blender程序。commandCallable的定义为:
初始化:
CommandExecutor的初始化参数就是前3个成员变量,将成员变量都赋值后,再将registry初始化,可以看到每种类型的任务都有它们对应的commandCallable,比如echo对应ce.cmdEcho,这就是worker支持的所有任务类型。
CommandLineRunner成员
注释已经描述了,CommandLineRunner是一个包裹exec.CommandContext的接口,exec.CommandContext就是Go语言中执行CMD命令的工具。这个接口有两个函数,CommandContext用来获取exec.Cmd,RunWithTextOutput用来执行CMD命令。
CLIRunner
实现CommandLineRunner这个接口的类叫做CLIRunner,CLIRunner中没有任何成员变量,单纯地实现了接口中的两个函数。
CommandContext函数
非常简单,创建并返回一个exec.Cmd指针。
RunWithTextOutput函数
这里只看它的核心代码部分,除了记录Cmd执行的日志以外,他唯一的功能就是execCmd.Start()开始执行Cmd命令。
CommandListener成员
CommandListener也是一个接口,用于将worker的任务执行日志和任务结果提交给manager,用来观测各个任务的详细执行情况。
LogProduced:用于上传日志到manager。
OutputProduced:用于上传任务输出(一般是渲染图片)到manager。
Listener
Listener是实现CommandListener接口的类。它的定义如下:
其中有3个成员变量,client用于与manager通信,buffer用来保存需要上传的信息,outputUploader实现上传操作,在它的初始化中,outputUploader也是需要client来进行初始化的,outputUploader就是Listener的核心。
LogProduced
LogProduced将最新的日志按行送到manager,其中调用了buffer.SendTaskUpdate方法,这是UpstreamBuffer中的一个方法。
日志传输的流程暂略。
OutputProduced
由outputUploader执行文件传输操作。
OutputUploader
这是执行真正文件传输操作的类,
可以看到,其中有一个FlamencoClient和一个queue,queue中保存了每一个任务的信息,信息由TaskID和Filename组成。
OutputUploader中的OutputProduced函数如下:
它并未做任务传输操作,而是将需要传输的文件加入队列。
OutputUploader中还有一个Run函数,它是这样的:
由此可以看出,worker的文件传输是异步的,它只要将需要传输的任务加入队列中,另一个goroutine会调用process函数来对每个任务进行处理,
process函数:
将需要上传的图片解析为JPEG格式,然后上传到manager。
CommandExecutor的其他成员函数
Run
Run函数是CommandExecutor执行cmd命令的函数,传入一个cmd,根据cmd.Name在registry中找到一个commandCallable类型的函数,这里叫做runner,然后调用这个函数。registry中保存了每个cmd.Name和需要执行的函数的映射,在CommandExecutor构建时就初始化了,比如”blender-render”对应cmdBlenderRender,cmdBlenderRender中就会调用CLIRunner的RunWithTextOutput来执行cmd命令。
总结
CommandExecutor是worker中用来执行cmd命令的函数,在flamenco中,manager中的每一项任务最终都具体到一个cmd命令,可能是简单的echo命令,可能是文件管理命令,最常用的是blender xxxx的后台渲染命令。CommandExecutor提供了命令执行,日志上传,命令执行结果上传的功能,不过它可以执行的命令是有限制的,在初始化时所有可执行的命令类型都被记录在registry中。