public virtual void testConcurrentExclusiveCorrelation() { InvocationLogListener.reset(); // given a process instance runtimeService.StartProcessInstanceByKey("testProcess"); // and two threads correlating in parallel ThreadControl thread1 = ExecuteControllableCommand(new ControllableMessageCorrelationCommand("Message", true)); thread1.ReportInterrupts(); ThreadControl thread2 = ExecuteControllableCommand(new ControllableMessageCorrelationCommand("Message", true)); thread2.ReportInterrupts(); // both threads open a transaction and wait before correlating the message thread1.WaitForSync(); thread2.WaitForSync(); // thread one correlates and acquires the exclusive lock thread1.MakeContinue(); thread1.WaitForSync(); // the service task was executed once Assert.AreEqual(1, InvocationLogListener.Invocations); // thread two attempts to acquire the exclusive lock but can't since thread 1 hasn't released it yet thread2.MakeContinue(); Thread.Sleep(2000); // let the first thread ends its transaction thread1.MakeContinue(); Assert.IsNull(thread1.Exception); // thread 2 can't continue because the event subscription it tried to lock was deleted thread2.WaitForSync(); Assert.True(thread2.Exception != null); Assert.True(thread2.Exception is ProcessEngineException); AssertTextPresent("does not have a subscription to a message event with name 'Message'", thread2.Exception.Message); // the first thread ended successfully without an exception thread1.Join(); Assert.IsNull(thread1.Exception); // the follow-up task was reached ITask afterMessageTask = taskService.CreateTaskQuery().First(); Assert.AreEqual(afterMessageTask.TaskDefinitionKey, "afterMessageUserTask"); // the service task was not executed a second time Assert.AreEqual(1, InvocationLogListener.Invocations); }
public virtual void FAILING_testConcurrentMixedCorrelationCase2() { InvocationLogListener.reset(); // given a process instance runtimeService.StartProcessInstanceByKey("testProcess"); // and two threads correlating in parallel (one exclusive, one non-exclusive) ThreadControl thread1 = ExecuteControllableCommand(new ControllableMessageCorrelationCommand("Message", false)); thread1.ReportInterrupts(); ThreadControl thread2 = ExecuteControllableCommand(new ControllableMessageCorrelationCommand("Message", true)); thread2.ReportInterrupts(); // both threads open a transaction and wait before correlating the message thread1.WaitForSync(); thread2.WaitForSync(); // thread one correlates and acquires no lock thread1.MakeContinue(); thread1.WaitForSync(); // thread two acquires a lock and succeeds because thread one hasn't acquired one thread2.MakeContinue(); thread2.WaitForSync(); // the service task was executed twice Assert.AreEqual(2, InvocationLogListener.Invocations); // thread one ends its transaction and blocks on flush when it attempts to Delete the event subscription thread1.MakeContinue(); Thread.Sleep(5000); Assert.IsNull(thread1.Exception); Assert.AreEqual(0, taskService.CreateTaskQuery().Count()); // thread 2 flushes successfully and releases the lock thread2.WaitUntilDone(); Assert.IsNull(thread2.Exception); ITask afterMessageTask = taskService.CreateTaskQuery().First(); Assert.NotNull(afterMessageTask); Assert.AreEqual(afterMessageTask.TaskDefinitionKey, "afterMessageUserTask"); // thread 1 flush fails with optimistic locking thread1.Join(); Assert.True(thread1.Exception != null); Assert.True(thread1.Exception is OptimisticLockingException); }