Activiti

Fill exception field when job fails

Details

  • Type: Task Task
  • Status: Resolved Resolved
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: None
  • Fix Version/s: 5.0.beta2
  • Component/s: Engine
  • Labels:
    None
  • Number of attachments :
    0

Description

@see DecrementJobRetriesCmd

// TODO store the exception in a byte array
// StringWriter stringWriter = new StringWriter();
// exception.printStackTrace(new PrintWriter(stringWriter));
// byte[] exceptionBytes = stringWriter.toString().getBytes();

Issue Links

Activity

Hide
Tom Baeyens added a comment -

@see ByteArrayEntity and VariableInstanceEntity.getByteArrayValue

introduce JobEntity.exceptionByteArray

Show
Tom Baeyens added a comment - @see ByteArrayEntity and VariableInstanceEntity.getByteArrayValue introduce JobEntity.exceptionByteArray
Hide
Tom Baeyens added a comment - - edited

suggestion:

  • move all cmds in org.activiti.engine.IMPL.jobexecutor to org.activiti.engine.impl.cmd
  • replace usages of ExecuteJobCmd with ExecuteJobsCmd and then remove ExecuteJobCmd
  • move the try-catch from ExecuteJobsRunnable into ExecuteJobsCmd
          try {
            commandExecutor.execute(new ExecuteJobsCmd(jobId));
          } catch (Throwable exception) {
            commandExecutor.execute(new DecrementJobRetriesCmd(jobExecutor, jobId, exception));
          }
    
  • then your test can use the managementService.executeJob method
Show
Tom Baeyens added a comment - - edited suggestion:
  • move all cmds in org.activiti.engine.IMPL.jobexecutor to org.activiti.engine.impl.cmd
  • replace usages of ExecuteJobCmd with ExecuteJobsCmd and then remove ExecuteJobCmd
  • move the try-catch from ExecuteJobsRunnable into ExecuteJobsCmd
          try {
            commandExecutor.execute(new ExecuteJobsCmd(jobId));
          } catch (Throwable exception) {
            commandExecutor.execute(new DecrementJobRetriesCmd(jobExecutor, jobId, exception));
          }
    
  • then your test can use the managementService.executeJob method
Hide
Frederik Heremans added a comment -

DecrementJobRetiesCmd is now invoked from within a TransactionListener, which is executed when the transaction (of the ExecuteJobCmd) has been rolled back. The rollback is triggered by re-throwing the RuntimeException which we caught in the execute() method on ExecuteJobCmd.

Since the DecrementJobRetriesCmd is executed after the ExecuteJobCmd transaction has been rolled back, it's safe to update the job's retries count an save the exception message and stacktrace.

Show
Frederik Heremans added a comment - DecrementJobRetiesCmd is now invoked from within a TransactionListener, which is executed when the transaction (of the ExecuteJobCmd) has been rolled back. The rollback is triggered by re-throwing the RuntimeException which we caught in the execute() method on ExecuteJobCmd. Since the DecrementJobRetriesCmd is executed after the ExecuteJobCmd transaction has been rolled back, it's safe to update the job's retries count an save the exception message and stacktrace.
Hide
Tom Baeyens added a comment -

when running the test suite with -Pcheckspring, the management service test still fails with this exception:

-------------------------------------------------------------------------------
Test set: org.activiti.engine.test.api.mgmt.ManagementServiceTest
-------------------------------------------------------------------------------
Tests run: 7, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.81 sec <<< FAILURE!
testGetJobExceptionStacktrace(org.activiti.engine.test.api.mgmt.ManagementServiceTest) Time elapsed: 0.423 sec <<< FAILURE!
junit.framework.AssertionFailedError: null
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.assertTrue(Assert.java:20)
at junit.framework.Assert.assertNotNull(Assert.java:214)
at junit.framework.Assert.assertNotNull(Assert.java:207)
at org.activiti.engine.test.api.mgmt.ManagementServiceTest.testGetJobExceptionStacktrace(ManagementServiceTest.java:89)
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 junit.framework.TestCase.runTest(TestCase.java:168)
at org.activiti.pvm.test.PvmTestCase.runTest(PvmTestCase.java:75)
at junit.framework.TestCase.runBare(TestCase.java:134)
at org.activiti.engine.impl.test.ActivitiInternalTestCase.runBare(ActivitiInternalTestCase.java:129)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
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.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)

could you analyse this, Frederik?

Show
Tom Baeyens added a comment - when running the test suite with -Pcheckspring, the management service test still fails with this exception: ------------------------------------------------------------------------------- Test set: org.activiti.engine.test.api.mgmt.ManagementServiceTest ------------------------------------------------------------------------------- Tests run: 7, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.81 sec <<< FAILURE! testGetJobExceptionStacktrace(org.activiti.engine.test.api.mgmt.ManagementServiceTest) Time elapsed: 0.423 sec <<< FAILURE! junit.framework.AssertionFailedError: null at junit.framework.Assert.fail(Assert.java:47) at junit.framework.Assert.assertTrue(Assert.java:20) at junit.framework.Assert.assertNotNull(Assert.java:214) at junit.framework.Assert.assertNotNull(Assert.java:207) at org.activiti.engine.test.api.mgmt.ManagementServiceTest.testGetJobExceptionStacktrace(ManagementServiceTest.java:89) 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 junit.framework.TestCase.runTest(TestCase.java:168) at org.activiti.pvm.test.PvmTestCase.runTest(PvmTestCase.java:75) at junit.framework.TestCase.runBare(TestCase.java:134) at org.activiti.engine.impl.test.ActivitiInternalTestCase.runBare(ActivitiInternalTestCase.java:129) at junit.framework.TestResult$1.protect(TestResult.java:110) at junit.framework.TestResult.runProtected(TestResult.java:128) at junit.framework.TestResult.run(TestResult.java:113) at junit.framework.TestCase.run(TestCase.java:124) at junit.framework.TestSuite.runTest(TestSuite.java:232) at junit.framework.TestSuite.run(TestSuite.java:227) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83) at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62) at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140) at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127) at org.apache.maven.surefire.Surefire.run(Surefire.java:177) 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.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345) at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009) could you analyse this, Frederik?
Hide
Frederik Heremans added a comment -

Problem is that the DecrementJobRetiesCmd is using the same transaction (and the same underlying JDBC connection) as the failing job.

10:47:49,045 FIN  | firing event rolled back...  [org.activiti.engine.impl.cfg.standalone.StandaloneIbatisTransactionContext]
10:47:49,046 FIN  |                                                                                                       [org.activiti.engine.impl.interceptor.DefaultCommandExecutor]
10:47:49,046 FIN  | --- starting DecrementJobRetriesCmd --------------------------------------------------------  [org.activiti.engine.impl.interceptor.DefaultCommandExecutor]
10:47:49,046 FIN  | Participating in existing transaction  [org.springframework.jdbc.datasource.DataSourceTransactionManager]
10:47:49,047 FIN  | ooo Connection Opened  [java.sql.Connection]

Since the DecrementJobRetriesCmd is called in a transaction listener on event ROLLED_BACK, I think something is wrong in transaction handling, since the already rolled-back transaction is used.

After the DecrementJobRetiesCmd has been executed, the exception thrown from the job (what the test is all about) is rethrown. After this, the log mentions this:

10:47:49,054 FIN  | Initiating transaction rollback on application exception
org.activiti.engine.ActivitiException: problem evaluating script: javax.script.ScriptException: java.lang.RuntimeException: This is an exception thrown from scriptTask

Logging comes from the org.springframework.transaction.support.TransactionTemplate class, which rolls back the transaction when an application exception occurs, which causes a rollback to be performed on the SQLConnection.

Rolling back JDBC transaction on Connection [conn4: url=jdbc:h2:mem:activiti user=SA]  [org.springframework.jdbc.datasource.DataSourceTransactionManager]

Connection (conn4) is the same connection that is used when starting the ExecuteJobCmd.

Show
Frederik Heremans added a comment - Problem is that the DecrementJobRetiesCmd is using the same transaction (and the same underlying JDBC connection) as the failing job.
10:47:49,045 FIN  | firing event rolled back...  [org.activiti.engine.impl.cfg.standalone.StandaloneIbatisTransactionContext]
10:47:49,046 FIN  |                                                                                                       [org.activiti.engine.impl.interceptor.DefaultCommandExecutor]
10:47:49,046 FIN  | --- starting DecrementJobRetriesCmd --------------------------------------------------------  [org.activiti.engine.impl.interceptor.DefaultCommandExecutor]
10:47:49,046 FIN  | Participating in existing transaction  [org.springframework.jdbc.datasource.DataSourceTransactionManager]
10:47:49,047 FIN  | ooo Connection Opened  [java.sql.Connection]
Since the DecrementJobRetriesCmd is called in a transaction listener on event ROLLED_BACK, I think something is wrong in transaction handling, since the already rolled-back transaction is used. After the DecrementJobRetiesCmd has been executed, the exception thrown from the job (what the test is all about) is rethrown. After this, the log mentions this:
10:47:49,054 FIN  | Initiating transaction rollback on application exception
org.activiti.engine.ActivitiException: problem evaluating script: javax.script.ScriptException: java.lang.RuntimeException: This is an exception thrown from scriptTask
Logging comes from the org.springframework.transaction.support.TransactionTemplate class, which rolls back the transaction when an application exception occurs, which causes a rollback to be performed on the SQLConnection.
Rolling back JDBC transaction on Connection [conn4: url=jdbc:h2:mem:activiti user=SA]  [org.springframework.jdbc.datasource.DataSourceTransactionManager]
Connection (conn4) is the same connection that is used when starting the ExecuteJobCmd.
Hide
Tom Baeyens added a comment -

i explicitely set the tx propagation in the spring tx interceptor to requires-new. that fixes this problem.

but now users will not be able to combine their transaction with the activiti service method transaction as is documented in the user guide.

that still needs to be addressed.

Show
Tom Baeyens added a comment - i explicitely set the tx propagation in the spring tx interceptor to requires-new. that fixes this problem. but now users will not be able to combine their transaction with the activiti service method transaction as is documented in the user guide. that still needs to be addressed.
Hide
Tom Baeyens added a comment -

I've split up the command executor in a tx required and a tx requires new version. And logged the work against ACT-45

Show
Tom Baeyens added a comment - I've split up the command executor in a tx required and a tx requires new version. And logged the work against ACT-45

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: