Rabbitmq调用FeignClient接口失败

文章目录

  • 一、框架及逻辑介绍
    • 1.背景服务介绍
    • 2.问题逻辑介绍
  • 二、代码
    • 1.A服务
    • 2.B服务
    • 3.C服务
  • 三、解决思路
    • 1.确认B调用C服务接口是否能正常调通
    • 2.确认B服务是否能正常调用A服务
    • 3.确认消息能否正常消费
    • 4.总结
  • 四、修改代码验证
    • 1.B服务异步调用C服务接口——失败
    • 2.将消费消息放到C服务中,消费时直接调用service——成功
  • 五、结论

走过路过大神帮忙给个正确解决方案~~~~~

一、框架及逻辑介绍

1.背景服务介绍

微服务结构,目前有A、B、C三个服务。

  • A服务:做一些工具类的功能
  • B服务:类似于门户,调用A、C服务来给到前端
  • C服务:基础模块,日志、权限、数据维护

2.问题逻辑介绍

  • A服务:实现blast功能,该功能是异步任务,需要几分钟的时间才能执行完成,所以采用了消息队列的方式通知功能完成,可查看数据。当代码执行完成之后通过rabbitmq发送消息到B服务
  • B服务:消费消息,调用C服务存储完成通知数据
  • C服务:提供FeignClient接口

二、代码

1.A服务

业务代码,详细的逻辑部分就不列出代码部分了, 测试确认无问题。

@Api(tags = "blast工具")
@RequiredArgsConstructor
@RequestMapping("blast")
@RestController
public class BlastController {private final BlastService blastService;@PostMapping("uniport")@ApiOperation("蛋白质序列对比")public ApiResponse<Boolean> check(@RequestBody BlastEntity blastEntity) {boolean flag = blastService.check(blastEntity);if(flag){return ApiResponse.success(flag);}else{return ApiResponse.failure("序列比对失败");}}@GetMapping("uniportDetail")@ApiOperation("蛋白质序列对比详情")public ApiResponse<BlastLogEntity> selectDetailById(@ApiParam("主键") @RequestParam("id") Integer id){return ApiResponse.success(blastService.selectDetailById(id));}
}

通过FeignClient提供功能接口给B服务(门户)

@FeignClient(name = "tool", url = "${customer.tool-url}")
public interface DataClient {@PostMapping("/blast/uniport")@ApiOperation("蛋白质序列对比")ApiResponse<Boolean> checkBlastUniprot(@RequestBody BlastEntity blastEntity);@GetMapping("/blast/uniportDetail")@ApiOperation("蛋白质序列对比详情")ApiResponse<BlastLogEntity> selectDetailById(@ApiParam("主键") @RequestParam("id") Integer id);
}

通过Rabbitmq发送消息

@Configuration
public class DirectRabbitMQConfig {//创建一个名为TestDirectExchange的Direct类型的交换机@BeanDirectExchange directExchange(){// durable:是否持久化,默认是false,持久化交换机。// autoDelete:是否自动删除,交换机先有队列或者其他交换机绑定的时候,然后当该交换机没有队列或其他交换机绑定的时候,会自动删除。// arguments:交换机设置的参数,比如设置交换机的备用交换机(Alternate Exchange),当消息不能被路由到该交换机绑定的队列上时,会自动路由到备用交换机return new DirectExchange(RabbitMqConstants.EXCHANGE_NAME,true,false);}//创建一个名为insertChassisDirectQueue的队列@Beanpublic Queue insertBlastDirectQueue(){// durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效// exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable// autoDelete:是否自动删除,有消息者订阅本队列,然后所有消费者都解除订阅此队列,会自动删除。// arguments:队列携带的参数,比如设置队列的死信队列,消息的过期时间等等。return new Queue(RabbitMqConstants.INSERT_BLAST_NAME,true);}//绑定交换机和队列@BeanBinding insertBlastDirect(){return BindingBuilder.bind(insertBlastDirectQueue()).to(directExchange()).with(RabbitMqConstants.INSERT_BLAST_KEY);}
}

2.B服务

消费消息,根据输出日志,可以看到消费消息成功。
但是走到apiClient.addLogMessage(logMessageEntity);不报错,C服务无响应,断点查看apiClient是可以看到C服务的信息localhost:8080的。

	@RabbitHandler@RabbitListener(bindings = {@QueueBinding(value = @Queue(value = INSERT_BLAST_NAME, durable = "true"),exchange = @Exchange(value = RabbitMqConstants.EXCHANGE_NAME),key = INSERT_BLAST_KEY)})public void insertBlast(Map map, Channel channel, Message message) {try {LOGGER.info("【生成的消息-blast序列比对结果】:{}", map.toString());channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);BlastLogEntity blastLogEntity = TypeSwitchUtil.toSnakeObject(JSON.toJSONString(map), BlastLogEntity.class);if (null == blastLogEntity || StringUtils.isEmpty(blastLogEntity.getContent())) {LOGGER.warn("【生成的消息-blast序列比对结果】:{}", map.toString());} else {LogMessageEntity logMessageEntity = new LogMessageEntity();logMessageEntity.setTargetId(blastLogEntity.getId());logMessageEntity.setUserId(String.valueOf(blastLogEntity.getUserId()));logMessageEntity.setMsgType(MsgStatusEnum.BLAST.getCode());logMessageEntity.setContent(MsgStatusEnum.BLAST.getMsg());apiClient.addLogMessage(logMessageEntity);}} catch (Exception e) {LOGGER.error(e.getMessage());}}

3.C服务

@FeignClient(name = "api", url = "${customer.url}", configuration = FeignConfig.class)
public interface ApiClient {@PostMapping("/cms/logMessage/add")@ApiOperation("新增系统通知发送记录")ApiResponse<Boolean> addLogMessage(@RequestBody LogMessageEntity logMessageEntity);
}

三、解决思路

1.确认B调用C服务接口是否能正常调通

在B服务中,通过Controller暴露接口,调用C服务FeignClient的@PostMapping("/cms/logMessage/add") 接口,通过swagger测试,数据成功存储到数据库中。

——接口没有问题,服务之间通信也没有问题

2.确认B服务是否能正常调用A服务

在B服务中,调用A服务接口,测试成功。

——服务之间通信没有问题

3.确认消息能否正常消费

在B服务中,调用A服务接口,A服务输出发送消息日志。B服务消费输出日志。

——消息无问题

4.总结

在这里插入图片描述

  • 服务之间通信没有问题
    在这里插入图片描述

  • 消息提供和消费没有问题

综合猜测可能是线程或事务问题。

四、修改代码验证

1.B服务异步调用C服务接口——失败

	@RabbitHandler@RabbitListener(bindings = {@QueueBinding(value = @Queue(value = INSERT_BLAST_NAME, durable = "true"),exchange = @Exchange(value = RabbitMqConstants.EXCHANGE_NAME),key = INSERT_BLAST_KEY)})public void insertBlast(Map map, Channel channel, Message message) {try {LOGGER.info("【生成的消息-blast序列比对结果】:{}", map.toString());channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);BlastLogEntity blastLogEntity = TypeSwitchUtil.toSnakeObject(JSON.toJSONString(map), BlastLogEntity.class);if (null == blastLogEntity || StringUtils.isEmpty(blastLogEntity.getContent())) {LOGGER.warn("【生成的消息-blast序列比对结果】:{}", map.toString());} else {LogMessageEntity logMessageEntity = new LogMessageEntity();logMessageEntity.setTargetId(blastLogEntity.getId());logMessageEntity.setUserId(String.valueOf(blastLogEntity.getUserId()));logMessageEntity.setMsgType(MsgStatusEnum.BLAST.getCode());logMessageEntity.setContent(MsgStatusEnum.BLAST.getMsg());CompletableFuture.runAsync(() -> {apiClient.addLogMessage(logMessageEntity);});}} catch (Exception e) {LOGGER.error(e.getMessage());}}

经测试,未能解决问题。

2.将消费消息放到C服务中,消费时直接调用service——成功

	@RabbitHandler@RabbitListener(bindings = {@QueueBinding(value = @Queue(value = "blast.insert.queue", durable = "true"),exchange = @Exchange(value = "tool"),key = "blast.insert")})public void insertBlast(Map map, Channel channel, Message message) {try {LOGGER.info("【生成的消息-blast序列比对结果】:{}", map.toString());channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);if (null == map || StringUtils.isEmpty(map.get("id").toString())) {LOGGER.warn("【生成的消息-blast序列比对结果】:{}", map.toString());} else {LogMessageEntity logMessageEntity = new LogMessageEntity();logMessageEntity.setTargetId(Integer.valueOf(map.get("id").toString()));logMessageEntity.setUserId(String.valueOf(map.get("user_id")));logMessageEntity.setMsgType(MsgStatusEnum.BLAST.getCode());logMessageEntity.setContent(MsgStatusEnum.BLAST.getMsg());logMessageService.save(logMessageEntity);}} catch (Exception e) {LOGGER.error(e.getMessage());}}

在这里插入图片描述

五、结论

在使用消息队列(MQ)调用FeignClient服务时,采取以下步骤:

  • 配置消息队列:首先,确保已正确配置和启动您所使用的消息队列,例如 RabbitMQ 或者 Kafka。

  • 创建消息生产者:创建一个消息生产者,用于将消息发送到消息队列。您可以使用消息队列的客户端库或框架来实现此功能。

  • 发送消息:在需要调用FeignClient服务的地方,将消息发送到消息队列。消息中包含请求的相关信息,例如服务名称、路径、参数等。

  • 创建消息消费者:创建一个消息消费者,用于从消息队列接收消息并处理。

  • 处理消息:在消息消费者中,处理接收到的消息。根据消息中的请求信息,使用FeignClient来调用相应的服务。

虽然通过直接调用service的方式成功进行数据存储了,这样做也没有违背原有的逻辑。
但是问题仍然没有一个正确的解决方式,希望走过路过的大神能指点一二,在线求助。

走过路过大神帮忙给个正确解决方案~~~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/434510.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二叉树的最近公共祖先,二叉搜索树的最近公共祖先(同一个思路)

目录 二叉树的最近公共祖先方法一&#xff08;时间复杂度O(N^2)&#xff09;方法二&#xff08;时间复杂度O(N)&#xff09; 二叉搜索树的最近公共祖先 二叉树的最近公共祖先 题目链接   二叉树的最近公共祖先   给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。  …

[BUUCTF]-PWN:babyfengshui_33c3_2016解析

又是一道堆题&#xff0c;先看保护 关键信息是32位&#xff0c;没开pie 直接看ida 大致是alloc创建堆块&#xff0c;free释放堆块&#xff0c;show查看堆块内容&#xff0c;fill填充堆块内容 其他的都没啥关键的要讲&#xff0c;但alloc那里非常需要解析一下 解释如上图 再具…

网站将http升级到https大概要多少费用

随着网络安全意识的不断提升&#xff0c;越来越多的网站正从传统的HTTP协议转向更安全的HTTPS协议。这一转变的核心在于部署SSL&#xff08;Secure Sockets Layer&#xff09;或TLS&#xff08;Transport Layer Security&#xff09;证书&#xff0c;以实现数据加密传输&#x…

phar反序列化漏洞

基础&#xff1a; Phar是一种PHP文件归档格式&#xff0c;它类似于ZIP或JAR文件格式&#xff0c;可以将多个PHP文件打包成一个单独的文件&#xff08;即Phar文件&#xff09;。 打包后的Phar文件可以像普通的PHP文件一样执行&#xff0c;可以包含PHP代码、文本文件、图像等各…

微信小程序(十八)组件通信(父传子)

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.组件属性变量的定义 2.组件属性变量的默认状态 3.组件属性变量的传递方法 解释一下为什么是父传子&#xff0c;因为组件是页面的一部分&#xff0c;数据是从页面传递到组件的&#xff0c;所以是父传子&#xf…

SpringMVC第六天(拦截器)

概念 拦截器(Interceptor)是一种动态拦截方法调用的机制&#xff0c;在SpringMVC中动态拦截控制器方法的执行 作用&#xff1a; 在指定的方法调用前后执行预先设定的代码 阻止原始方法的执行 拦截器与过滤器的区别 归属不同&#xff1a;Filter属于Servlet技术&#xff0c;I…

k8s从初识到上天系列第二篇:kubernetes的组件和架构

&#x1f609;&#x1f609; 欢迎加入我们的学习交流群呀&#xff01; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring、SpringSecurity、Docker、Grpc、各种MQ、Rpc、SpringCloud等等很多应用和源码…

UDF学习(五)FLUENT UDF-DEFINE_INIT宏和DEFINE_DELTAT宏和DEFINE_ADJUST宏

FLUENT UDF-DEFINE_INIT宏 以此为例&#xff1a; DEFINE_INIT(init,domain)//一般格式 #include"udf.h" DEFINE_INIT(init,domain) { cell_t c; Thread *thread; real xc[ND_ND],x,y; thread_loop_c(thread,domain) { begin_c_loop(c,thread) } C_CENTROID(xc,c,t…

【C++】C++ 入门 — 命名空间,输入输出,函数新特性

C 1 前言2 命名空间2.1 概念引入2.2 开始使用2.3 投入应用 3 输入与输出3.1 基础知识3.2 开始使用3.3 注意局限 4 函数新特性4.1 缺省参数4.1.1 开始使用4.1.2 注意事项 4.2 函数重载4.2.1 开始使用4.2.2 如何实现 Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读下…

Python算法题集_接雨水

本文为Python算法题集之一的代码示例 题目42&#xff1a;接雨水 说明&#xff1a;给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1]…

银行数据仓库体系实践(11)--数据仓库开发管理系统及开发流程

数据仓库管理着整个银行或公司的数据&#xff0c;数据结构复杂&#xff0c;数据量庞大&#xff0c;任何一个数据字段的变化或错误都会引起数据错误&#xff0c;影响数据应用&#xff0c;同时业务的发展也带来系统不断升级&#xff0c;数据需求的不断增加&#xff0c;数据仓库需…

HBase入门:运行机制

文章目录 HBase 系统架构客户端ZooKeeper 服务器Master 主服务器Region 服务器 Region 服务器工作原理用户读写数据的过程缓存的刷新StoreFile合并 Store 的工作原理HLog 的工作原理 HBase 系统架构 HBase 的系统架构包括客户端、ZooKeeper 服务器、Master 主服务器、Region服…