Search code examples
hibernategrailsgrails-ormexecutorservice

Grails and background tasks


User fills some form where he sets parameters for report generation. He submits the form, server validates the parameters, returns message that everything is ok to the user and generates the report. After report generation is finished, user gets email with link to report.

What is the proper way to achieve this in grails? At the moment I have a service that generates the report, it looks like this:

@Transactional
class AnalyticsService {

    ExecutorService executor = Executors.newSingleThreadExecutor()

    def buildExportAndSendMail() {
        executor.execute {
            //GENERATE REPORT AND SEND MAIL. USES GORM.
        }
    }

    @PreDestroy
    void shutdown() {
        executor.shutdownNow()
    }
}

My controller action looks like this:

def generateReport(ReportParams command) {
    if(!command.hasErrors()) {
        analyticsService.buildExportAndSendMail()
        render([success:true, html:"Your report is being generated."] as JSON)
    } else {
        ...
    }
}

However, service is throwing an error when trying to acces domain object fields:

Exception in thread "pool-8-thread-1" 
Error |
org.hibernate.LazyInitializationException: could not initialize proxy - no Session

What would be a proper way for doing this in grails?


Solution

  • The issue here is that you are creating a new thread and it's not bound to a Hibernate session. Creating one is easy enough. It doesn't matter what domain class you use. For example:

    def buildExportAndSendMail() {
      executor.execute {
        SomeDomainClass.withNewSession { session ->
          //GENERATE REPORT AND SEND MAIL. USES GORM.
        }
      }
    }
    

    You can read more about withNewSession in the documentation.