背景介绍

通常业务中需要用到定时执行功能,我用hangfire搭建了一个调度服务,这个调度服务是独立于业务逻辑的,具体可以参考文章:https://github.com/yuzd/Hangfire.HttpJob/wiki

也就是说只要我有了这个调度服务后,只要提供给我的接口 我就可以调度它(比如在xx点xx分运行,或者每隔xx分运行,或者每周一8点运行等等)。

但是有一个问题,对方的接口是调用成功还是失败完全取决于对方的接口设计!

有的接口被设计成 请求的StatusCode 是200的是代表接口成功,非200的代表接口失败。

有的接口被设计成返回的json结构有一个特定的字段来代表接口调用成功还是失败,例如:success字段。比如返回的结构大概这样子:{"success":false,"data":"xxxx"}

等等,这些都是case by case ,不同的写接口的人定的规则可能不一样,通过webjob的调用方式如何动态的验证成功还是失败呢?

如上面提到动态的验证结果,我分了2种情况处理:要么看Response返回的statuscode,要么是看返回的结果里面的指定字段来判断!

1. 根据Response返回的statuscode

statuscode很好做,我在设计Hangfire.HttpJob这个扩展插件时是可以在外部设置一个验证委托

默认的返回的statuscode 小于 400 则认为http请求是成功的,否则失败

2. 返回的结果里面的指定字段来判断

我采用EL表达式来实现的,EL表达式将请求的返回体设置为json变量,然后在表达式中可以直接以属性的方式到值,表达式返回布尔类型。

针对不同的接口,我可以设置一个独立的表达式来进行判断!

首先在job添加的时候设置el表达式!如下图

如何写EL表达式:(很简单,返回的结构体是什么字段就可以用什么字段)

接口的返回体是一个string。我先将这个String转成json类型(dynamic)

然后是采用Spring.EL表达式实现的。CallbackEL表达式的返回类型是布尔类型

返回体在表达式里面是有下面2个变量:

  • #resultBody 是返回体的 string

  • #result 是返回体的 json体(根据上面转的,如果上面是非json格式的那就不能使用这个变量了)

比如说我调用的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));    }
///         /// 用EL表达式动态判断是否执行成功        ///         ///         private static bool InvokeSpringElCondition(string placeholder,string result, PerformContext context,Dictionary<string, object> param)        {            try            {                try                {                    param["result"] = JsonConvert.DeserializeObject(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 param 作为参数,使用#参数来引用。如果你的参数是string 那么可以写c#中string的所有方法比如 StarsWith,EndsWith,Equals 等等如果你的参数类型是一个dynamic,那你就可以直接像使用js的对象属性一样

Callback功能设计

举例:

我们调用了A接口,如果A接口成功我们想把A接口的返回值作为请求参数再去调用B接口。

如果A接口失败在调用C接口通知错误!

参考ajax的callback设计

如上图 可以自行添加 Success 或者 Fail 作为回调

如果定义了Success 那么父job执行成功没有报错则运行 Success回调

如果定义了Fail 那么父job执行失败 则运行 Fail回调

Success 里面还可以定义 Success 和 Fail

Fail 里面还可以定义 Success 和 Fail 如下图:

回调的Json参数

字段 说明
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 -> Success BB

JobA本身执行错误的话则会走重试逻辑(如果开启重试的话),重试到顶后 进入 Fail B, Fail B 执行成功 则进入 Success BB。如果Success BB 执行成功,那么 JobA 则认为是成功的,否则认为失败!

如果:JobA -》 Fail B -> Fail BB

JobA本身执行错误的话则会走重试逻辑(如果开启重试的话),重试到顶后 进入 Fail B, Fail B 执行失败 则进入 Fail BB 。Fail BB 执行失败,那么 JobA 认为失败!

Fail B 执行成功 进入 Success C, Success C,执行成功 认为 JobA 认为成功,否则 Job A 认为失败!

总结:如果回调 则会按照设置的回调一路走下去,看最后一个回调是否成功。如果成功 则认为整个链路执行成功,否则认为失败!

回调的代码实现是一个递归的方式调用

为了实现回调能够把上一个运行的结果最为参数,开发了占位符(placeholder)功能

也为了更好的扩展占位符功能,

首先要介绍下 dashbord里面的 全局配置 功能 如下图:

  • 全局配置 :存储在当前目录下的 hangfire_global.json 文件(可以在StartUp代码修改HangfireHttpJobOptions.GlobalSettingJsonFilePath值指定其他地方

这个功能为了介绍重复的配置,可以集中配置一些参数,然后给各个job去使用!

占位符功能采用Spring.EL表达式实现的。

字符串中placeholder替换逻辑

  • 第一步:把字符串中的 ${xxx} 的xxx全部替换成 全局配置里面的值

  • 第二步:把字符串中的 #{yyy} 的yyy全部按照SpringEL表达式逻辑运行后的值进行替换

比如:上图中你在全局配置了一个参数叫test

Data:"你好呀:${test}"

在运行时会被替换成 =》    你好呀:1

例如:使用父job的返回值传给 callback

如果运行失败传给callback是报错信息

例如:使用时间替换

可以直接在 #{} 方法里面用DateTime这个变量 这个变量和c#一样的功能

比如

  • #{DateTime.Now} 代表运行时的当前时间+时分秒

  • #{DateTime.Today} 代表运行时的当天

  • #{DateTime.Today.AddDays(-1)} 代表运行时的昨天

  • #{DateTime.Today.AddDays(1)} 代表运行时的明天

总结:

以上 hangfire的webjob调度扩展组件(https://github.com/yuzd/Hangfire.HttpJob/wiki)

已经非常灵活了,基于hangfire的核心调度功能,加上webjob的调用方式,很方便的把业务逻辑分离出来!

不管业务接口如何写,基于EL表达式都可以准确的判断出来执行成功还是失败,根据回调功能很方便的执行链式调用和错误通知!

把执行结果转成json对象报错_给Hangfire的webjob增加callback和动态判断返回结果功能设计...相关推荐

  1. 把执行结果转成json对象报错_于一次JSON格式错误 之 手把手带你走一波FastJSON将对象转成JSON字符串流程...

    一.前言 最近老大说要新增一个试用广告的功能,我巴拉巴拉的从之前推送广告那里将代码cv过来,然后跟老大说搞定了!过一会老大说返回的json格式不对!于是乎我瞧了瞧: { "adsArea1& ...

  2. 把执行结果转成json对象报错_关于JSON转换成对象 报错LinkedHashMap不能直接转成对象...

    /** * 用于ajax请求,返回非list的的包装类 * @author dev4 * */ public class ObjectResult implements Serializable{ / ...

  3. 把执行结果转成json对象报错_JSONObject获取值后为一个对象,将对象转为JSONObject时报错...

    将json字符串转化成List>对象 Map map = new HashMap(); map.put("key1", "value1"); map.pu ...

  4. spring boot ajax 415,解决@RequestBody接收json对象报错415的问题

    @RequestBody接收json对象报错415 前端请求: $.ajax({ url: basePath() + "/index/login.do", type : " ...

  5. 关于:js使用$.parseJSON字符串转json对象报错Uncaught SyntaxError- Unexpected token o in JSON at position 1

    今天使用js使用$.parseJSON字符串转json对象报错Uncaught SyntaxError- Unexpected token o in JSON at position 1,一直找不到原 ...

  6. Ajax传JSON对象报错:JSON parse error: Unrecognized token ‘ids‘: was expecting (‘true‘, ‘false‘ or ‘null‘);

    org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unrecognized t ...

  7. word2013插入excel对象报错_在 Excel 电子表格中插入对象

    如果在 Excel 或支持 OLE 的任何程序(如 Word)之间复制信息,可以将信息复制为 链接对象 或 嵌入对象 . 链接对象与嵌入对象之间的主要区别是数据存储位置,以及对象在放置到目标位置后 目 ...

  8. android studio访问webservice如何传递类对象报错_小白学习web service,这是最最最基础的了,只用JDK还不会吗?...

    Java Web Service实践 Web Service直接翻译就是网络服务. 主要为了解决各种语言,各种系统之间不兼容,通过SOAP(简单对象访问协议)实现互联互通. 其核心就是这个SOAP,通 ...

  9. word2013插入excel对象报错_教大家Excel2013如何插入对象文件

    近日有关于Excel2013如何插入对象文件的问题受到了很多网友们的关注,大多数网友都想要知道Excel2013如何插入对象文件的具体情况,那么关于到Excel2013如何插入对象文件的相关信息,小编 ...

最新文章

  1. Python OpenCV应用K均值聚类进行颜色量化
  2. CentOS 7.7 安装cmake3
  3. 10 个 Python 工程师,9 个不合格!!
  4. python batch normalization_Batch Normalization 引出的一系列问题
  5. python中turtle画酷炫图案-酷炫的动态可视化交互大屏,用Excel就能做!
  6. uniGUI试用笔记(二)
  7. 奇葩说之RTC的那些事
  8. 使用 C# 编程对RTF文档的支持
  9. CentOS查看分区的方式
  10. 从RT-Thread RTOS接触到的3个算法
  11. 蓝桥杯 ADV-173算法提高 淘淘的名单
  12. AssetBundle的一些笔记
  13. Java程序员面试宝典--面向对象的基本概念
  14. de4dot 反混淆工具使用
  15. 【金九银十】Java微服务面试题,看到你就是赚到
  16. centos刻录工具_centos u盘引导制作工具
  17. springmvc ResponseEntity 下载文件损坏问题解决方法
  18. c语言中的绝对值符号
  19. 2020蚂蚁森林自动收能量-保持更新
  20. Chart.js给图片数据动态赋值

热门文章

  1. 好的安排小明(南阳19)(DFS)
  2. nginx限制ip访问(转)
  3. linux 报错 bash ‘/bin/sh: Syntax error: “(” unexpected
  4. 为SQL缓存通知启用数据库
  5. sgu 196 Matrix Multiplication
  6. 交互式 shell 玩转 Python
  7. 某些数组和字符串类型转换(转)
  8. hdu4707 Pet(bfs dfs,vector)
  9. Oracle RAC搭建
  10. 在线图片转base64工具