一般业务中须要用到定时执行功能,我用hangfire搭建了一个调度服务,这个调度服务是独立于业务逻辑的,具体能够参考文章:https://github.com/yuzd/Hangfire.HttpJob/wikigit
也就是说只要我有了这个调度服务后,只要提供给个人接口 我就能够调度它(好比在xx点xx分运行,或者每隔xx分运行,或者每周一8点运行等等)。github
可是有一个问题,对方的接口是调用成功仍是失败彻底取决于对方的接口设计!web
有的接口被设计成 请求的StatusCode 是200的是表明接口成功,非200的表明接口失败。ajax
有的接口被设计成返回的json结构有一个特定的字段来表明接口调用成功仍是失败,例如:success字段。好比返回的结构大概这样子: {"success":false,"data":"xxxx"}json
等等,这些都是case by case ,不一样的写接口的人定的规则可能不同,经过webjob的调用方式如何动态的验证成功仍是失败呢?c#
如上面提到动态的验证结果,我分了2种状况处理:要么看Response返回的statuscode,要么是看返回的结果里面的指定字段来判断!app
statuscode很好作,我在设计Hangfire.HttpJob这个扩展插件时是能够在外部设置一个验证委托lua
默认的返回的statuscode 小于 400 则认为http请求是成功的,不然失败spa
我采用EL表达式来实现的,EL表达式将请求的返回体设置为json变量,而后在表达式中能够直接以属性的方式到值,表达式返回布尔类型。插件
针对不一样的接口,我能够设置一个独立的表达式来进行判断!
首先在job添加的时候设置el表达式!以下图
如何写EL表达式:(很简单,返回的结构体是什么字段就能够用什么字段)
接口的返回体是一个string。我先将这个String转成json类型(dynamic)
而后是采用Spring.EL表达式实现的。 CallbackEL表达式的返回类型是布尔类型
返回体在表达式里面是有下面2个变量:
好比说我调用的httpjob 返回体是
{"Success":false,"Info":"test"}
那么我能够这么写
"CallbackEL": "#result.Success"
也能够这么写
"CallbackEL": "#result.Info.Equals('ok')"
Spring.EL是我从Spring.Net里面剥离出来的一个组件,能够从nuget里面引用,支持net45和netstandard2.0
//检查是否有设置EL表达式 if (!string.IsNullOrEmpty(item.CallbackEL)) { var elResult = InvokeSpringElCondition(item.CallbackEL, result, context, new Dictionary<string, object> { { "resultBody", result } }); if (!elResult) { throw new HttpStatusCodeException(item.CallbackEL, result); } RunWithTry(() => context.WriteLine($"【{Strings.CallbackELExcuteResult}:Ok 】" + item.CallbackEL)); }
/// <summary> /// 用EL表达式动态判断是否执行成功 /// </summary> /// <returns></returns> private static bool InvokeSpringElCondition(string placeholder,string result, PerformContext context,Dictionary<string, object> param) { try { try { param["result"] = JsonConvert.DeserializeObject<ExpandoObject>(result); } catch (Exception) { //ignore } var parameterValue = ExpressionEvaluator.GetValue(null, placeholder, param); return (bool)parameterValue; } catch (Exception e) { context.WriteLine($"【{Strings.CallbackELExcuteError}】" + placeholder); context.WriteLine(e); return false; } }
调用对象 ExpressionEvaluator 传 Dictionary<string, object> param 做为参数,使用#参数来引用。若是你的参数是string 那么能够写c#中string的全部方法好比 StarsWith,EndsWith,Equals 等等
若是你的参数类型是一个dynamic,那你就能够直接像使用js的对象属性同样
举例:
咱们调用了A接口,若是A接口成功咱们想把A接口的返回值做为请求参数再去调用B接口。
若是A接口失败在调用C接口通知错误!
参考ajax的callback设计
若是定义了Success 那么父job执行成功没有报错则运行 Success回调
若是定义了Fail 那么父job执行失败 则运行 Fail回调
Success 里面还能够定义 Success 和 Fail
Fail 里面还能够定义 Success 和 Fail 以下图:
字段 | 说明 |
---|---|
Url | 请求Url |
Method | Post,Get |
Data | Post时能够填,支持占位符(具体请看下面的介绍) |
ContentType | application/json |
Timeout | 超时(毫秒) |
BasicUserName | basicauth用户名 |
BasicPassword | basicauth密码 |
AgentClass | 基于jobAgent开发的httpjob须要填 |
Headers | key:value 的jsonstring "{"key":,"value"}" |
注意:回调不是做为新的的HangfireHttpJob执行的,是依附在最顶级的父Job的!
举例:
JobA自己执行错误的话则会走重试逻辑(若是开启重试的话),重试到顶后 进入 Fail B, Fail B 执行成功 则进入 Success BB。若是Success BB 执行成功,那么 JobA 则认为是成功的,不然认为失败!
JobA自己执行错误的话则会走重试逻辑(若是开启重试的话),重试到顶后 进入 Fail B, Fail B 执行失败 则进入 Fail BB 。Fail BB 执行失败,那么 JobA 认为失败!
Fail B 执行成功 进入 Success C, Success C,执行成功 认为 JobA 认为成功,不然 Job A 认为失败!
也为了更好的扩展占位符功能,
首先要介绍下 dashbord里面的 全局配置 功能 以下图:
这个功能为了介绍重复的配置,能够集中配置一些参数,而后给各个job去使用!
占位符功能采用Spring.EL表达式实现的。
字符串中placeholder替换逻辑
Data:"你好呀:${test}"
在运行时会被替换成 =》 你好呀:1
若是运行失败传给callback是报错信息
能够直接在 #{} 方法里面用DateTime这个变量 这个变量和c#同样的功能
好比