命令中心服务 - Nebula.Fides
使用场景
这里涉及3个对象:
- 命令的发布者:【云端】的各个应用程序
 - 命令的执行者:【云下】的客户端程序
 - 二端的协调者:用于连接各个应用程序和云下客户端。
 
执行流程介绍:
- 客户端,以死循环的方式执行下面步骤:
- (1)使用HTTP协议调用Fides拉取命令
 - (4)在获取到命令后,交给后台线程来执行,然后上传命令的执行结果(5)
 - (_)重新执行 (1) 步骤
 
 - Fides,监听HTTP端口,接收命令的发布和上传结果
- (3)当接收到命令发布时,Fides会立即将命令返回给客户端
 - 如果没有收到命令,Fides则将客户端的请求挂起,直到命令出现或者达到超时
 
 - 应用程序
- (2)根据业务需要,使用HTTP协议给Fides发布命令,并等待执行结果(6)
 
 
Fides的价值:
- 简化【云端应用程序】调用【云下客户端】的过程
 - 对于【云端应用程序】来说,只需要对Fides发起一次HTTP调用即可得到结果
 
API调用
应用程序--发布命令--并等待--执行结果
POST http://hostxxxxxx/v20/api/fides/cmd/publish HTTP/1.1
Content-Type: application/json
x-token: .......jwt-token.................
{
  "ActionName": "actionx",
  "ClientId": "Client-3",
  "Caller": "Caller-111"
}
响应示例:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
    "ServerId": "e0e194b0bbc84db98f8eac6dff15e126",
    "CallbackId": "5459a6fe9b7541d59b9af53358044da8",
    "TenantId": "FISHDEV-WIN10",
    "ClientId": "Client-3",
    "ClientReceiveTime": "2022-07-13T18:51:34.9975544+08:00",
    "ClientStartTime": "2022-07-13T18:51:34.9975544+08:00",
    "ClientEndTime": "2022-07-13T18:51:34.9975544+08:00",
    "ServerReceiveTime": "2022-07-13T18:51:35.0918622+08:00",
    "ResponseResult": "FISHDEV-WIN10#Client-3 execute actionx OK!",
    "ClientAddition": "addition is ..xxx..",
    "RequestId": "92eeaf0008e543a6846748d6a0615892"
}
请求体的数据结构如下:
public sealed class PublishArgs
{
    /// 要执行命令的客户端Id
    [Required]
    public string ClientId { get; set; }
    /// 命令名称
    [Required]
    public string ActionName { get; set; }
    /// 命令的调用参数
    public string Args { get; set; }
    /// 命令的发布者
    public string Sender { get; set; }
    /// 发布命令的功能场景
    public string Caller { get; set; }
    /// 命令是单向的,不需要等待执行结果
    public int IsOneWay { get; set; }
    /// 服务端的最大等待时间
    public int ServerWaitSecond { get; set; }
    /// 客户端的最大等待时间
    public int ClientWaitSecond { get; set; }
    /// 客户端执行命令时,如果发生异常,最大的允许多少次重试
    public int MaxExecuteRetryCount { get; set; }
    /// 客户端上传结果时,如果发生异常,最大的允许多少次重试
    public int MaxUploadRetryCount { get; set; }
    /// 客户端遇到异常做重试时,中间间隔多少秒
    public int ErrorWaitSecond { get; set; }
}
响应体的数据结构如下:
public sealed class CommandResult
{
    /// 服务端节点Id
    public string ServerId { get; set; }
    /// 服务端当前请求ID
    public string RequestId { get; set; }
    /// 引用 ClientCommand.CallbackId
    public string CallbackId { get; set; }
    public string TenantId { get; set; }
    public string ClientId { get; set; }
    public DateTime ClientReceiveTime { get; set; }
    public DateTime ClientStartTime { get; set; }
    public DateTime ClientEndTime { get; set; }
    public DateTime ServerReceiveTime { get; set; }
    /// 客户端的响应结果
    public string ResponseResult { get; set; }
    /// 客户端的结果响应类型,,可参考HTTP的 Content-Type 响应头
    public string ResponseContentType { get; set; }
    /// 客户端的结果响应的编码方式,可参考HTTP的 Content-Encoding 响应头
    public string ResponseContentEncoding { get; set; }
    /// 客户端的一些附加描述信息
    public string ClientAddition { get; set; }
    /// 客户端引发的异常类型
    public string ExecptionType { get; set; }
    /// 客户端引发的异常描述
    public string ExecptionText { get; set; }    
}
客户端--拉取命令
GET http://hostxxxxxx/v20/api/fides/cmd/pull HTTP/1.1
x-token: .......jwt-token.................
x-expect-count: 1
x-client-timeoutms: 110000
请求头说明:
- x-expect-count  明确告诉服务端:一次只返回一个ClientCommand对象。
如果不指定,则以数组形式返回(也只有一个对象)
这个参数主要是为了解决兼容性问题,建议指定,且 value 只能设置为 1 - x-client-timeoutms  告诉服务端:客户端的超时时间
如果不指定此参数,请求在服务端挂起的时间由服务端决定,此时客户端的超时时间必须大于服务端的挂起时间。 
响应示例:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
    "CommandGuid": "ddcd19465244410cb8030701e029bf97",
    "CreateTime": "2022-07-13T19:06:55.8980434+08:00",
    "ServerId": "e0e194b0bbc84db98f8eac6dff15e126",
    "CallbackId": "f5e12ca3a8f642f8a2945009461e6769",
    "ActionName": "actionx",
    "Caller": "Caller-111",
    "IsOneWay": 0,
    "UserId": "11111",
    "UserType": "admin",
    "TenantId": "FISHDEV-WIN10",
    "ClientId": "Client-3",
    "ClientWaitSecond": 0,
    "ServerWaitSecond": 20,
    "MaxExecuteRetryCount": 0,
    "MaxUploadRetryCount": 0,
    "ErrorWaitSecond": 0
}
响应体的数据结构如下:
public sealed class ClientCommand
{
    /// 服务端创建时间
    public DateTime CreateTime { get; set; }
    /// 服务端节点Id
    public string ServerId { get; set; }
    /// 客户端上传结果后的回调通知ID,【始终应该使用这个字段来做唯一ID】
    public string CallbackId { get; set; }
    public string ActionName { get; set; }
    public string Args { get; set; }
    public string Caller { get; set; }
    /// 命令是单向的,不需要等待执行结果
    public int IsOneWay { get; set; }
    public string UserId { get; set; }
    public string UserType { get; set; }
    public string TenantId { get; set; }
    public string ClientId { get; set; }
    public int ClientWaitSecond { get; set; }
    public int ServerWaitSecond { get; set; }
    public int MaxExecuteRetryCount { get; set; }
    public int MaxUploadRetryCount { get; set; }
    public int ErrorWaitSecond { get; set; }
}
客户端--上传--命令执行结果
POST http://hostxxxxxx/v20/api/fides/cmd/upload HTTP/1.1
Content-Type: application/json
x-token: .......jwt-token.................
{
    "CallbackId": "..............",
    "ClientStatus": 200,
    "ResponseResult": ".............."
}
响应示例:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
    "CallbackId": "5459a6fe9b7541d59b9af53358044da8"
}
请求体的数据结构如下:
public sealed class UploadArgs
{
    /// 引用 ClientCommand.CallbackId
    [Required]
    public string CallbackId { get; set; }
    public DateTime ClientReceiveTime { get; set; }
    public DateTime ClientStartTime { get; set; }
    public DateTime ClientEndTime { get; set; }
    /// 客户端对于执行结果的状态码表示
    public int ClientStatus { get; set; }
    /// 客户端的响应结果
    public string ResponseResult { get; set; }
    /// 客户端的结果响应类型
    public string ResponseContentType { get; set; }
    /// 客户端的结果响应的编码方式,可参考HTTP的 Content-Encoding 响应头
    public string ResponseContentEncoding { get; set; }
    /// 客户端的一些附加描述信息
    public string ClientAddition { get; set; }
    /// 客户端引发的异常类型
    public string ExecptionType { get; set; }
    /// 客户端引发的异常描述
    public string ExecptionText { get; set; }
}
日志&问题排查
发布命令时,Fides会记录一些重要数据到Oprlog日志中,可以在Venus/Kibana中查看:
日志字段含意
- bizId: CallbackId
 - bizName: ActionName
 - text2: TenantId
 - text3: ClientId
 
其中 CallbackId 贯穿了 publish/pull/upload 3个阶段,可以根据此数据来查询对应的日志: