背景
公司中间件团队使用了 com.mongodb.event.CommandListener 来对mongodb 打点监控。当我们使用 RocketMQ 调用 mongodb 保存数据的时候没有看到任何异常产生。在我们将 RocketMQ 改用中间件代理,产生了大量的DuplicateKeyException日志,一度怀疑是否中间件的 RocketMQ 代理有问题, 分析源码没有。
分析原因
-
消费消息的时候,异常如果自己不捕获打印的话,会被ConsumeMessageConcurrentlyService默认忽略掉,所以不会有日志打印出来
-
CommandListener 的 commandFailed 方法不会监控到一些业务异常例如 DuplicateKeyException, IncorrectResultSizeDataAccessException
解决
- 当发生 DuplicateKeyException 的时候仍然会进入到 CommandListener d的 commandSucceeded 方法, 并且 CommandSucceededEvent 的响应内容是
{ "ok" : 1, "n" : 0, "opTime" : { "ts" : { "$timestamp" : { "t" : 1619575210, "i" : 4 } }, "t" : { "$numberLong" : "22" } }, "electionId" : { "$oid" : "7fffffff0000000000000016" }, "writeErrors" : [{ "index" : 0, "code" : 11000, "errmsg" : "E11000 duplicate key error collection: test.test index: test_id_1 dup key: { : 1 }" }] }
我们可以通过获取 commandSucceededEvent 中的 writeErrors 来判断执行是否出现了错误
CollectionUtils.isEmpty(commandSucceededEvent.getResponse().getArray("writeErrors"))
- 制定代码规范,MessageListenerConcurrently 中必须要自己捕获异常