使用来自 grails 4.0.3 中的 rabbit mq 消费者的数据在服务层的数据库中保存记录的问题

Posted

技术标签:

【中文标题】使用来自 grails 4.0.3 中的 rabbit mq 消费者的数据在服务层的数据库中保存记录的问题【英文标题】:Problems in saving records in database in service tier with data which comes from rabbit mq consumer in grails 4.0.3 【发布时间】:2021-12-17 23:28:29 【问题描述】:

我在使用带有 Grails 4.0.3 的 RabbitMQ 队列时遇到了麻烦。和 JVM 版本:1.8.0_275

我不知道为什么,但我有一个兔子消费者,他必须做一些事情,其中​​包括将数据保存在数据库中,如下所示。

package br.gov.cmb.pid.consumers

import br.gov.cmb.pid.domain.RenachLog
import br.gov.cmb.pid.services.PidService
import com.budjb.rabbitmq.consumer.MessageContext
import com.budjb.rabbitmq.publisher.RabbitMessagePublisher
import grails.gorm.transactions.Transactional
import org.grails.web.json.JSONObject

@Transactional
class PidIssuingConsumer 
    RabbitMessagePublisher rabbitMessagePublisher
    static rabbitConfig = [ queue : "detran.transactions.191.requests" ]
    JSONObject icomResp

    def handleMessage(Map body, MessageContext messageContext) 
        icomResp = new JSONObject().accumulate("status","No response available")
        PidService pidService

        try 
            icomResp = sendPidIssuingToIcom(body as JSONObject)
            publishIcomPidIssuingResponse(icomResp)
            saveRenachLog(icomResp.toString())
         catch (Exception e)
            saveRenachLog(e.getLocalizedMessage())
            println(e.printStackTrace())
        
    

    def sendPidIssuingToIcom(JSONObject pidIssuingDocument)
        println(pidIssuingDocument)
        return pidIssuingDocument
    

    def publishIcomPidIssuingResponse(JSONObject pidIssuingResponse)
        rabbitMessagePublisher.send 
            exchange = "detran.requests"
            routingKey = "191-response"
            body = [response: pidIssuingResponse]
        
        println(pidIssuingResponse)
    

    def saveRenachLog(String icomResp)
        RenachLog renachLog = new RenachLog()
        renachLog.transactionId = "191"
        renachLog.loggedOn = new Date()
        renachLog.logDescription = icomResp
        renachLog.save(flush: true, failOnError: true)
    

此代码按预期工作,但我希望方法 saveRenachLog 和 sendPidIssuingToIcom 在我的服务 PidService.groovy 中分离。不幸的是,当我这样做时,我会在下面收到此异常消息。

本地化消息:

完整的堆栈跟踪。 2021-11-03 12:06:52.399 错误 --- [pool-5-thread-1] cbrconsumer.AbstractConsumerContext:未处理的异常 java.lang.reflect.InvocationTargetException 在消费者 br.gov.cmb 的 RabbitMQ 消息处理程序中捕获。 pid.consumers.PidIssuingConsumer

java.lang.reflect.InvocationTargetException: null
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.budjb.rabbitmq.consumer.LegacyConsumerContext.process(LegacyConsumerContext.groovy:262)
        at com.budjb.rabbitmq.consumer.LegacyConsumerContext$process.callCurrent(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:156)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:168)
        at com.budjb.rabbitmq.consumer.AbstractConsumerContext.deliverMessage(AbstractConsumerContext.groovy:325)
        at com.budjb.rabbitmq.consumer.ConsumerContext$deliverMessage.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
        at com.budjb.rabbitmq.consumer.RabbitMessageHandler.handleDelivery(RabbitMessageHandler.groovy:100)
        at com.rabbitmq.client.impl.ConsumerDispatcher$5.run(ConsumerDispatcher.java:149)
        at com.rabbitmq.client.impl.ConsumerWorkService$WorkPoolRunnable.run(ConsumerWorkService.java:104)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException: Cannot invoke method saveRenachLog() on null object
        at org.codehaus.groovy.runtime.NullObject.invokeMethod(NullObject.java:91)
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:43)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.NullCallSite.call(NullCallSite.java:34)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
        at br.gov.cmb.pid.consumers.PidIssuingConsumer.$tt__handleMessage(PidIssuingConsumer.groovy:25)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1217)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
        at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:1011)
        at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:994)
        at org.codehaus.groovy.runtime.InvokerHelper.invokeMethodSafe(InvokerHelper.java:97)
        at br.gov.cmb.pid.consumers.PidIssuingConsumer$_handleMessage_closure1.doCall(PidIssuingConsumer.groovy)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:263)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
        at groovy.lang.Closure.call(Closure.java:405)
        at groovy.lang.Closure.call(Closure.java:421)
        at grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
        at grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)
        at br.gov.cmb.pid.consumers.PidIssuingConsumer.handleMessage(PidIssuingConsumer.groovy)
        ... 20 common frames omitted

我已经在我的服务代码中插入了@Transactional。

你能帮帮我吗?

【问题讨论】:

【参考方案1】:

注意 1:当您将方法移至服务时,我无法判断代码的外观,您可能希望包含失败的代码。

也就是说,您似乎是在方法中声明您的 pidService,默认值为 null,然后尝试在其上调用方法。

尝试改变这个:

RabbitMessagePublisher rabbitMessagePublisher
static rabbitConfig = [ queue : "detran.transactions.191.requests" ]
JSONObject icomResp

def handleMessage(Map body, MessageContext messageContext) 
    icomResp = new JSONObject().accumulate("status","No response available")
    PidService pidService

到这里:

RabbitMessagePublisher rabbitMessagePublisher
PidService pidService
static rabbitConfig = [ queue : "detran.transactions.191.requests" ]
JSONObject icomResp

def handleMessage(Map body, MessageContext messageContext) 
    icomResp = new JSONObject().accumulate("status","No response available")

注意 pidService 现在是类属性,而不是方法局部变量。如果 PidService 是 Grails 中的另一个服务,那么它应该可以正常注入并且可以使用。至少这应该清除您的 NullPointerException,并让您继续进行调试。

【讨论】:

感谢您的评论。它现在工作正常。

以上是关于使用来自 grails 4.0.3 中的 rabbit mq 消费者的数据在服务层的数据库中保存记录的问题的主要内容,如果未能解决你的问题,请参考以下文章

来自另一个域类的属性的 Grails 自定义验证器

在 grails 中处理来自服务的错误

来自服务的 Grails Spring Security 身份验证

Mongodb身份验证不适用于grails,而是来自控制台

Grails 文档中的自定义事件监听器示例

来自Grails的原子馈送