1
votes

My grails app is sending emails asynchronously in one of its controllers. Asynchronously, because it should be sent after a lengthy process. I am currently using the executor plugin and the runAsync closure.

def sendEmails() {
    ...
    runAsync {

        // ... Some lengthy process before emailing
        myMailService.send('[email protected]', 
            g.render(template: 'mail', model: resultOfLengthyProcess))

    }
    ...
}

I am running it after the lengthy process, because the model in the render function call contains the result of that process.

I want to use the g.render() method because the email is a big gsp template with lots of pictures and content.

Now that g.render call will fail, because it is being called from another thread. It throws java.lang.IllegalStateException with the message:

No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

How can I solve this issue? I am open to any answers/suggestions.

1

1 Answers

0
votes

You need a request in order to use render directly, and with an asynchronous block you loose it.

However you should be able to achieve what you want by injecting the PageRender in your controller and calling it from the async block.

class MyController {
    grails.gsp.PageRenderer groovyPageRenderer

    def sendEmails() {
        // ... Some lengthy process before emailing
        myMailService.send(
            '[email protected]', 
            groovyPageRenderer.render(template: 'mail', model: resultOfLengthyProcess)
        )
    }
}

I would suggest to use JMS (with the jms plugin), encapsulating the lengthy process in a service.