public virtual void TestBackoffDecrease()
        {
            // when starting a number of process instances process instance
            for (var i = 0; i < 15; i++)
            {
                var id = _engineRule.RuntimeService.StartProcessInstanceByKey("simpleAsyncProcess").Id;
            }

            // ensure that both acquisition threads acquire the same jobs thereby provoking an optimistic locking exception
            JobAcquisitionTestHelper.SuspendInstances(_engineRule.ProcessEngine, 12);

            // when starting job execution, both acquisition threads Wait before acquiring something
            _jobExecutor1.Start();
            _acquisitionThread1.WaitForSync();
            _jobExecutor2.Start();
            _acquisitionThread2.WaitForSync();

            // when continuing acquisition thread 1
            // then it is able to acquire and execute all jobs
            _acquisitionThread1.MakeContinueAndWaitForSync();

            // when continuing acquisition thread 2
            // acquisition fails with an OLE
            _acquisitionThread2.MakeContinueAndWaitForSync();

            _jobExecutor1.Shutdown();
            _acquisitionThread1.WaitUntilDone();
            _acquisitionThread2.MakeContinueAndWaitForSync();

            // such that acquisition thread 2 performs backoff
            var jobExecutor2WaitEvents = ((RecordingAcquireJobsRunnable)_jobExecutor2.AcquireJobsRunnable).WaitEvents;

            Assert.AreEqual(1, jobExecutor2WaitEvents.Count);

            // when in the next cycles acquisition thread2 successfully acquires jobs without OLE for n times
            JobAcquisitionTestHelper.ActivateInstances(_engineRule.ProcessEngine, 12);

            for (var i = 0; i < BackoffDecreaseThreshold; i++)
            {
                // backoff has not decreased yet
                Assert.True(jobExecutor2WaitEvents[i].TimeBetweenAcquisitions > 0);

                _acquisitionThread2.MakeContinueAndWaitForSync(); // acquire
                _acquisitionThread2.MakeContinueAndWaitForSync(); // continue after acquisition with next cycle
            }

            // it decreases its backoff again
            var lastBackoff = jobExecutor2WaitEvents[BackoffDecreaseThreshold].TimeBetweenAcquisitions;

            Assert.AreEqual(0, lastBackoff);
        }
        public virtual void TestBackoffOnOptimisticLocking()
        {
            // when starting a number of process instances process instance
            for (var i = 0; i < 9; i++)
            {
                _engineRule.RuntimeService.StartProcessInstanceByKey("simpleAsyncProcess"); //.Id;
            }

            // ensure that both acquisition threads acquire the same jobs thereby provoking an optimistic locking exception
            JobAcquisitionTestHelper.SuspendInstances(_engineRule.ProcessEngine, 6);

            // when starting job execution, both acquisition threads Wait before acquiring something
            _jobExecutor1.Start();
            _acquisitionThread1.WaitForSync();
            _jobExecutor2.Start();
            _acquisitionThread2.WaitForSync();

            // when having both threads acquire jobs
            // then both Wait before committing the acquiring transaction (AcquireJobsCmd)
            _acquisitionThread1.MakeContinueAndWaitForSync();
            _acquisitionThread2.MakeContinueAndWaitForSync();

            // when continuing acquisition thread 1
            _acquisitionThread1.MakeContinueAndWaitForSync();

            // then it has not performed Waiting since it was able to acquire and execute all jobs
            var jobExecutor1WaitEvents = _jobExecutor1.AcquireJobsRunnable.WaitEvents;

            Assert.AreEqual(1, jobExecutor1WaitEvents.Count);
            Assert.AreEqual(0, jobExecutor1WaitEvents.ElementAt(0).TimeBetweenAcquisitions);

            // when continuing acquisition thread 2, acquisition fails with an OLE
            _acquisitionThread2.MakeContinueAndWaitForSync();

            // and has performed backoff
            var jobExecutor2WaitEvents = _jobExecutor2.AcquireJobsRunnable.WaitEvents;

            Assert.AreEqual(1, jobExecutor2WaitEvents.Count);
            var waitEvent = jobExecutor2WaitEvents.ElementAt(0);

            // we don't know the exact Wait time,
            // since there is random jitter applied
            JobAcquisitionTestHelper.AssertInBetween(BaseBackoffTime, BaseBackoffTime + BaseBackoffTime / 2, waitEvent.TimeBetweenAcquisitions);

            // when performing another cycle of acquisition
            JobAcquisitionTestHelper.ActivateInstances(_engineRule.ProcessEngine, 6);
            _acquisitionThread1.MakeContinueAndWaitForSync();
            _acquisitionThread2.MakeContinueAndWaitForSync();

            // and thread 1 again acquires all jobs successfully
            _acquisitionThread1.MakeContinueAndWaitForSync();

            // while thread 2 again fails with OLE
            _acquisitionThread2.MakeContinueAndWaitForSync();

            // then thread 1 has tried to acquired 3 jobs again
            var jobExecutor1AcquisitionEvents = _jobExecutor1.AcquireJobsRunnable.AcquisitionEvents;
            var secondAcquisitionAttempt      = jobExecutor1AcquisitionEvents.ElementAt(1);

            Assert.AreEqual(3, secondAcquisitionAttempt.NumJobsToAcquire);

            // and not Waited
            jobExecutor1WaitEvents = _jobExecutor1.AcquireJobsRunnable.WaitEvents;
            Assert.AreEqual(2, jobExecutor1WaitEvents.Count);
            Assert.AreEqual(0, jobExecutor1WaitEvents.ElementAt(1).TimeBetweenAcquisitions);

            // then thread 2 has tried to acquire 6 jobs this time
            var jobExecutor2AcquisitionEvents = _jobExecutor2.AcquireJobsRunnable.AcquisitionEvents;

            secondAcquisitionAttempt = jobExecutor2AcquisitionEvents.ElementAt(1);
            Assert.AreEqual(6, secondAcquisitionAttempt.NumJobsToAcquire);

            // and again increased its backoff
            jobExecutor2WaitEvents = _jobExecutor2.AcquireJobsRunnable.WaitEvents;
            Assert.AreEqual(2, jobExecutor2WaitEvents.Count);
            var  secondWaitEvent     = jobExecutor2WaitEvents.ElementAt(1);
            long expectedBackoffTime = BaseBackoffTime * BackoffFactor; // 1000 * 2^1

            JobAcquisitionTestHelper.AssertInBetween(expectedBackoffTime, expectedBackoffTime + expectedBackoffTime / 2, secondWaitEvent.TimeBetweenAcquisitions);
        }