Search code examples
grailsjobsactiviti

Expired activiti jobs throwing exception while server startup - Grails


This is with regard to activiti workflow timer jobs in grails application.

While starting the grails app with expired jobs, exception is thrown for normal grails features such as log and methods of domain classes.

For eg:

Caused by: groovy.lang.MissingPropertyException: No such property: log for class: com.service.common.UtilityService
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:49)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassGetPropertySite.getProperty(PogoMetaClassGetPropertySite.java:50)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:239)
    at com.service.common.UtilityService.insertToQueue(UtilityService.groovy:370)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.activiti.engine.impl.javax.el.BeanELResolver.invoke(BeanELResolver.java:479)
    ... 71 more

This happens in dev environment running the app from Spring STS. We are using activiti plugin 5.8.2 for grails (1.3.6)

After the web-app is started up completely, the jobs (schedule to a time after startup) run properly and no missing property exception is thrown.

Even though we can fix the of missing property issue for log by using private static final log = LogFactory.getLog(this) instead, then any reference to domain classes throw an error, like using get or find method.

eg:

Caused by: groovy.lang.MissingMethodException: No signature of method: static com.domain.wr.WorkRequest.read() is applicable for argument types: (java.lang.String) values: [44700]
Possible solutions: getId(), getAt(java.lang.String), setId(java.lang.Long), grep(java.lang.Object), each(groovy.lang.Closure), find(groovy.lang.Closure)
    at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1357)
    at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1343)
    at groovy.lang.ExpandoMetaClass.invokeStaticMethod(ExpandoMetaClass.java:1082)
    at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:50)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
    at com.service.common.UtilityService.insertToQueue(UtilityService.groovy:373)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.activiti.engine.impl.javax.el.BeanELResolver.invoke(BeanELResolver.java:479)
    ... 71 more

Activiti Configuration

Config.groovy

// Added by the Grails Activiti plugin:
activiti {
      processEngineName = "activiti-engine-default"
      databaseType = "oracle"
      deploymentName = appName
      history = "audit" // "none", "activity", "audit" or "full"
      sessionUsernameKey = "username"
      useFormKey = true
      deploymentResources = ["classpath:activiti/escalation/WorkRequest.bpmn20.xml"]

}

Config.properties

activiti.processEngineName =activiti-engine-default
activiti.databaseSchemaUpdate =true 
activiti.jobExecutorActivate =true
activiti.mailServerHost = "mail1.net"
activiti.mailServerPort = 25
activiti.mailServerUsername = ""
activiti.mailServerPassword = ""
activiti.mailServerDefaultFrom = ""

This is killing my application as a downtime makes the workflow unusable with timer tasks.


Solution

  • This issue got solved.
    1) Edit Config.groovy and disable activiti during startup

     activiti {
              processEngineName = "activiti-engine-default"
              databaseType = "oracle"
              disabled = true
              deploymentName = appName
              sessionUsernameKey = "username"
              useFormKey = true
              deploymentResources = []
        }
    

    2) add the initialization of Activiti Objects in the init method of User BootStrap

    def init = { servletContext ->
    
        org.springframework.context.ApplicationContext ctx = ServletContextHolder.getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
        def bb = new grails.spring.BeanBuilder(ctx)
        bb.beans {
            //println "Activiti Process Engine Initialization..."
            customDbIdGenerator(com.mycompany.activiti.customDbIdGenerator){
                idBlockSize=CH.config.activiti.idBlockSize?:100
            }
            processEngineConfiguration(org.activiti.spring.SpringProcessEngineConfiguration) {
                processEngineName = CH.config.activiti.processEngineName?:ActivitiConstants.DEFAULT_PROCESS_ENGINE_NAME
                databaseType = CH.config.activiti.databaseType?:ActivitiConstants.DEFAULT_DATABASE_TYPE
                databaseSchemaUpdate = CH.config.activiti.databaseSchemaUpdate ? CH.config.activiti.databaseSchemaUpdate.toString() : ActivitiConstants.DEFAULT_DATABASE_SCHEMA_UPDATE
                deploymentName = CH.config.activiti.deploymentName?:ActivitiConstants.DEFAULT_DEPLOYMENT_NAME
                deploymentResources = CH.config.activiti.deploymentResources?:ActivitiConstants.DEFAULT_DEPLOYMENT_RESOURCES
                jobExecutorActivate = CH.config.activiti.jobExecutorActivate?:ActivitiConstants.DEFAULT_JOB_EXECUTOR_ACTIVATE
                      history = CH.config.activiti.history?:ActivitiConstants.DEFAULT_HISTORY
                mailServerHost = CH.config.activiti.mailServerHost?:ActivitiConstants.DEFAULT_MAIL_SERVER_HOST
                mailServerPort = CH.config.activiti.mailServerPort?:ActivitiConstants.DEFAULT_MAIL_SERVER_PORT
                mailServerUsername = CH.config.activiti.mailServerUsername
                mailServerPassword = CH.config.activiti.mailServerPassword
                mailServerDefaultFrom = CH.config.activiti.mailServerDefaultFrom?:ActivitiConstants.DEFAULT_MAIL_SERVER_FROM
                dataSource = ref("dataSource")
                transactionManager = ref("transactionManager")
                idGenerator= ref("customDbIdGenerator")
            }
    
              processEngine(org.activiti.spring.ProcessEngineFactoryBean) {
                  processEngineConfiguration = ref("processEngineConfiguration")
              }
    
            runtimeService(processEngine:"getRuntimeService")
            repositoryService(processEngine:"getRepositoryService")
            taskService(processEngine:"getTaskService")
            managementService(processEngine:"getManagementService")
            identityService(processEngine:"getIdentityService")
            historyService(processEngine:"getHistoryService")
            formService(processEngine:"getFormService")
    
            activitiService(org.grails.activiti.ActivitiService) {
                runtimeService = ref("runtimeService")
                taskService = ref("taskService")
                identityService = ref("identityService")
                formService = ref("formService")
            }
        }
        println "## Registering Beans ##";
        bb.registerBeans(ctx);
        ctx.getBean("processEngine");
    
        println "Bean Count2 "+ctx.getBeanDefinitionCount();
    }
    

    Please note that DB Id Generator used is custom and can be replaced by the default one.