Repository: mercedes-benz/sechub
Issue: Optimistic Locks on multiple PDS - members leads to duplicated Job execution

##### Note
- The origin problem is described here: the occurrence of optimistic lock entries.
- This was more or less only annoying
- After anlaysing the mentioned problem source it became clear that on a clusters this also did execute the JOBS multiple times (see comment below with title  "Critical bug detected")

## Problem

When PDS is using PostgreSQL as database, then Optimistic Lock problems occur. It does not matter if the cluster consists of only a single instance or more than one instance. The more instances the PDS cluster has, the more likely it becomes for the optimistic lock problem to occur.

## Analysis

### 1 PDS:

~~~
pds-gosec_1     | 2021-07-13 08:55:05.950  INFO 8 --- [0.0-8444-exec-2] c.d.s.pds.job.PDSFileUploadJobService    : Upload file sourcecode.zip for job b135466c-f2bd-434a-a900-10ffcb84c903 to storage
pds-gosec_1     | 2021-07-13 08:55:05.951  INFO 8 --- [0.0-8444-exec-2] c.d.s.s.s.spring.SharedVolumeJobStorage  : job:b135466c-f2bd-434a-a900-10ffcb84c903: storing sourcecode.zip in path pds/GOSEC_CLUSTER
pds-gosec_1     | 2021-07-13 08:55:05.953  INFO 8 --- [0.0-8444-exec-2] c.d.s.s.s.spring.SharedVolumeJobStorage  : job:b135466c-f2bd-434a-a900-10ffcb84c903: storing sourcecode.zip.checksum in path pds/GOSEC_CLUSTER
loadbalancer_1  | 172.20.0.1 - admin [13/Jul/2021:08:55:05 +0000] "POST /api/job/b135466c-f2bd-434a-a900-10ffcb84c903/upload/sourcecode.zip HTTP/1.1" 200 25 "-" "curl/7.58.0"
pds-gosec_1     | 2021-07-13 08:55:06.138  INFO 8 --- [0.0-8444-exec-1] c.d.s.pds.job.PDSJobTransactionService   : Mark job b135466c-f2bd-434a-a900-10ffcb84c903 as ready to start
loadbalancer_1  | 172.20.0.1 - admin [13/Jul/2021:08:55:06 +0000] "PUT /api/job/b135466c-f2bd-434a-a900-10ffcb84c903/mark-ready-to-start HTTP/1.1" 200 0 "-" "curl/7.58.0"
loadbalancer_1  | 172.20.0.1 - admin [13/Jul/2021:08:55:06 +0000] "GET /api/job/b135466c-f2bd-434a-a900-10ffcb84c903/status HTTP/1.1" 200 165 "-" "curl/7.58.0"
pds-gosec_1     | 2021-07-13 08:55:06.583  INFO 8 --- [pool-2-thread-1] c.d.s.p.execution.PDSExecutionCallable   : Prepare execution of job b135466c-f2bd-434a-a900-10ffcb84c903
pds-gosec_1     | 2021-07-13 08:55:06.601  INFO 8 --- [pool-2-thread-1] c.d.sechub.pds.job.PDSWorkspaceService   : Unzipped 2 files to /workspace/workspace/b135466c-f2bd-434a-a900-10ffcb84c903/upload/unzipped/sourcecode
pds-gosec_1     | 2021-07-13 08:55:06.602  INFO 8 --- [pool-2-thread-1] c.d.s.p.execution.PDSExecutionCallable   : Start launcher script for job b135466c-f2bd-434a-a900-10ffcb84c903
pds-gosec_1     | 2021-07-13 08:55:06.603 ERROR 8 --- [   scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task
pds-gosec_1     | 
pds-gosec_1     | org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [com.daimler.sechub.pds.job.PDSJob] with identifier [b135466c-f2bd-434a-a900-10ffcb84c903]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.daimler.sechub.pds.job.PDSJob#b135466c-f2bd-434a-a900-10ffcb84c903]
pds-gosec_1     | 	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:315)
pds-gosec_1     | 	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233)
pds-gosec_1     | 	at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:566)
…
pds-gosec_1     | Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.daimler.sechub.pds.job.PDSJob#b135466c-f2bd-434a-a900-10ffcb84c903]
~~~

The exception occurs after starting the execution script and before the job is done.

### 2 PDS

~~~
ds-gosec_1     | 2021-07-13 08:49:11.955  INFO 7 --- [0.0-8444-exec-1] c.d.s.pds.job.PDSFileUploadJobService    : Upload file sourcecode.zip for job 07411f09-ed0c-4d24-804d-b900f801e7a7 to storage
pds-gosec_1     | 2021-07-13 08:49:11.957  INFO 7 --- [0.0-8444-exec-1] c.d.s.s.s.spring.SharedVolumeJobStorage  : job:07411f09-ed0c-4d24-804d-b900f801e7a7: storing sourcecode.zip in path pds/GOSEC_CLUSTER
pds-gosec_1     | 2021-07-13 08:49:11.959  INFO 7 --- [0.0-8444-exec-1] c.d.s.s.s.spring.SharedVolumeJobStorage  : job:07411f09-ed0c-4d24-804d-b900f801e7a7: storing sourcecode.zip.checksum in path pds/GOSEC_CLUSTER
loadbalancer_1  | 172.20.0.1 - admin [13/Jul/2021:08:49:11 +0000] "POST /api/job/07411f09-ed0c-4d24-804d-b900f801e7a7/upload/sourcecode.zip HTTP/1.1" 200 0 "-" "curl/7.58.0"
pds-gosec_1     | 2021-07-13 08:49:12.162  INFO 7 --- [0.0-8444-exec-5] c.d.s.pds.job.PDSJobTransactionService   : Mark job 07411f09-ed0c-4d24-804d-b900f801e7a7 as ready to start
loadbalancer_1  | 172.20.0.1 - admin [13/Jul/2021:08:49:12 +0000] "PUT /api/job/07411f09-ed0c-4d24-804d-b900f801e7a7/mark-ready-to-start HTTP/1.1" 200 0 "-" "curl/7.58.0"
pds-gosec_2     | 2021-07-13 08:49:12.201  INFO 8 --- [pool-2-thread-2] c.d.s.p.execution.PDSExecutionCallable   : Prepare execution of job 07411f09-ed0c-4d24-804d-b900f801e7a7
pds-gosec_2     | 2021-07-13 08:49:12.213 ERROR 8 --- [   scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task
pds-gosec_2     | 
pds-gosec_2     | org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [com.daimler.sechub.pds.job.PDSJob] with identifier [07411f09-ed0c-4d24-804d-b900f801e7a7]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.daimler.sechub.pds.job.PDSJob#07411f09-ed0c-4d24-804d-b900f801e7a7]
…
pds-gosec_2     | Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.daimler.sechub.pds.job.PDSJob#07411f09-ed0c-4d24-804d-b900f801e7a7]
~~~

The issue occurs after starting the execution script and before the job is done in `pds-gosec_2`. `pds-gosec_1` handled the file upload.

### 3 PDS

~~~
pds-gosec_2     | 2021-07-13 08:27:32.122  INFO 10 --- [0.0-8444-exec-9] c.d.s.pds.job.PDSFileUploadJobService    : Upload file sourcecode.zip for job d40bba6b-f344-4446-846d-067e57df4ed6 to storage
pds-gosec_2     | 2021-07-13 08:27:32.123  INFO 10 --- [0.0-8444-exec-9] c.d.s.s.s.spring.SharedVolumeJobStorage  : job:d40bba6b-f344-4446-846d-067e57df4ed6: storing sourcecode.zip in path pds/GOSEC_CLUSTER
pds-gosec_2     | 2021-07-13 08:27:32.123  INFO 10 --- [0.0-8444-exec-9] c.d.s.s.s.spring.SharedVolumeJobStorage  : job:d40bba6b-f344-4446-846d-067e57df4ed6: storing sourcecode.zip.checksum in path pds/GOSEC_CLUSTER
loadbalancer_1  | 172.20.0.1 - admin [13/Jul/2021:08:27:32 +0000] "POST /api/job/d40bba6b-f344-4446-846d-067e57df4ed6/upload/sourcecode.zip HTTP/1.1" 200 25 "-" "curl/7.58.0"
pds-gosec_2     | 2021-07-13 08:27:32.301  INFO 10 --- [0.0-8444-exec-8] c.d.s.pds.job.PDSJobTransactionService   : Mark job d40bba6b-f344-4446-846d-067e57df4ed6 as ready to start
loadbalancer_1  | 172.20.0.1 - admin [13/Jul/2021:08:27:32 +0000] "PUT /api/job/d40bba6b-f344-4446-846d-067e57df4ed6/mark-ready-to-start HTTP/1.1" 200 0 "-" "curl/7.58.0"
loadbalancer_1  | 172.20.0.1 - admin [13/Jul/2021:08:27:32 +0000] "GET /api/job/d40bba6b-f344-4446-846d-067e57df4ed6/status HTTP/1.1" 200 165 "-" "curl/7.58.0"
pds-gosec_1     | 2021-07-13 08:27:32.612  INFO 8 --- [pool-2-thread-3] c.d.s.p.execution.PDSExecutionCallable   : Prepare execution of job d40bba6b-f344-4446-846d-067e57df4ed6
pds-gosec_3     | 2021-07-13 08:27:32.618  INFO 7 --- [pool-2-thread-4] c.d.s.p.execution.PDSExecutionCallable   : Prepare execution of job d40bba6b-f344-4446-846d-067e57df4ed6
pds-gosec_1     | 2021-07-13 08:27:32.627  INFO 8 --- [pool-2-thread-3] c.d.s.p.execution.PDSExecutionCallable   : Had optimistic lock problem on update for job d40bba6b-f344-4446-846d-067e57df4ed6 - do retry nr.1
pds-gosec_1     | 2021-07-13 08:27:32.642  INFO 8 --- [pool-2-thread-3] c.d.s.p.execution.PDSExecutionCallable   : Had optimistic lock problem on update for job d40bba6b-f344-4446-846d-067e57df4ed6 - do retry nr.2
pds-gosec_3     | 2021-07-13 08:27:32.640 ERROR 7 --- [   scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task
pds-gosec_3     | 
pds-gosec_3     | org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [com.daimler.sechub.pds.job.PDSJob] with identifier [d40bba6b-f344-4446-846d-067e57df4ed6]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.daimler.sechub.pds.job.PDSJob#d40bba6b-f344-4446-846d-067e57df4ed6]
…
pds-gosec_3     | Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.daimler.sechub.pds.job.PDSJob#d40bba6b-f344-4446-846d-067e57df4ed6]
~~~

In this case, both `pds-gosec_1` and `pds-gosec_3` prepare for the job execution. `pds-gosec_1` reports it had an optimistic lock problem, but `pds-gosec_3` throws the actual exception. `pds-gosec_2` handled the file upload.

## Wanted

The PDS should scale up to 100s of instances without having optimistic lock problems.

[optimistic_lock_exception.txt](https://github.com/Daimler/sechub/files/6809885/optimistic_lock_exception.txt)


Changed files:
sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario5/Scenario5.java
sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/ScenarioInitializer.java
sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobRepositoryImpl.java
sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/IntegrationTestDefaultExecutorConfigurations.java
sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobRepositoryCustom.java
sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario6/Scenario6.java
sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario9/Scenario9.java
sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/api/ExecutionConstants.java
sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobTransactionService.java
sechub-pds/src/main/java/com/daimler/sechub/pds/execution/PDSExecutionCallable.java
sechub-pds/src/test/java/com/daimler/sechub/pds/batch/PDSBatchTriggerServiceTest.java
sechub-integrationtest/src/test/java/com/daimler/sechub/integrationtest/scenario5/PDSCodeScanJobScenario5IntTest.java
sechub-pds/src/main/java/com/daimler/sechub/pds/batch/PDSBatchTriggerService.java
sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/IntegrationTestDefaultProfiles.java

diff --git a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/api/ExecutionConstants.java b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/api/ExecutionConstants.java
index c54f3fb56..3ec235a73 100644
--- a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/api/ExecutionConstants.java
+++ b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/api/ExecutionConstants.java
@@ -36,6 +36,6 @@ public class ExecutionConstants {
      * profiles. This profile contains executors of PDS integration test in version V1, using SARIF - but DOES NOT reuse SecHub storage
      * 
      */
-    public static final String DEFAULT_PROFILE_4_ID = IntegrationTestDefaultProfiles.PROFILE_4_PDS_CODESCAN_SARIF_NO_SECHUB_STORAGE_USED.id;  
+    public static final String DEFAULT_PROFILE_4_ID = IntegrationTestDefaultProfiles.PROFILE_4_NO_STORAGE_REUSED__PDS_CODESCAN_SARIF.id;  
     
 }
diff --git a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/IntegrationTestDefaultExecutorConfigurations.java b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/IntegrationTestDefaultExecutorConfigurations.java
index e058a90ac..dab4c7d92 100644
--- a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/IntegrationTestDefaultExecutorConfigurations.java
+++ b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/IntegrationTestDefaultExecutorConfigurations.java
@@ -25,6 +25,16 @@ public class IntegrationTestDefaultExecutorConfigurations {
 
     private static final List<TestExecutorConfig> registeredConfigurations = new ArrayList<>();
     
+    private enum StorageType{
+        REUSE_SECHUB_DATA(),
+        
+        DO_NOT_REUSE_SECHUB_DATA,
+        
+        ;
+
+        
+    }
+    
     private static final String INTTEST_NAME_PREFIX = "INTTEST_";
     
     public static final TestExecutorConfig NETSPARKER_V1 = defineNetsparkerConfig();
@@ -37,11 +47,32 @@ public class IntegrationTestDefaultExecutorConfigurations {
     public static final String PDS_CODESCAN_VARIANT_D="d";
     public static final String PDS_CODESCAN_VARIANT_E="e";
     
-    public static final TestExecutorConfig PDS_V1_CODE_SCAN_A = definePDSScan(PDS_CODESCAN_VARIANT_A,false,PDSIntTestProductIdentifier.PDS_INTTEST_CODESCAN);
-    public static final TestExecutorConfig PDS_V1_CODE_SCAN_B = definePDSScan(PDS_CODESCAN_VARIANT_B,true,PDSIntTestProductIdentifier.PDS_INTTEST_CODESCAN);
-    public static final TestExecutorConfig PDS_V1_CODE_SCAN_C = definePDSScan(PDS_CODESCAN_VARIANT_C,true,(String)null,true);// no identifier set, will not work...
-    public static final TestExecutorConfig PDS_V1_CODE_SCAN_D = definePDSScan(PDS_CODESCAN_VARIANT_D,false,PDSIntTestProductIdentifier.PDS_INTTEST_PRODUCT_CS_SARIF,true);
-    public static final TestExecutorConfig PDS_V1_CODE_SCAN_E = definePDSScan(PDS_CODESCAN_VARIANT_E,false,PDSIntTestProductIdentifier.PDS_INTTEST_PRODUCT_CS_SARIF,false);
+    /* @formatter:off */
+    public static final TestExecutorConfig PDS_V1_CODE_SCAN_A = definePDSScan(
+                                                PDS_CODESCAN_VARIANT_A,false,
+                                                PDSIntTestProductIdentifier.PDS_INTTEST_CODESCAN, 
+                                                StorageType.REUSE_SECHUB_DATA);
+    
+    public static final TestExecutorConfig PDS_V1_CODE_SCAN_B = definePDSScan(
+                                                PDS_CODESCAN_VARIANT_B,true,
+                                                PDSIntTestProductIdentifier.PDS_INTTEST_CODESCAN, 
+                                                StorageType.REUSE_SECHUB_DATA);
+    
+    public static final TestExecutorConfig PDS_V1_CODE_SCAN_C = definePDSScan(
+                                                PDS_CODESCAN_VARIANT_C,true,
+                                                (String)null,
+                                                StorageType.REUSE_SECHUB_DATA);// no identifier set, will not work...
+    
+    public static final TestExecutorConfig PDS_V1_CODE_SCAN_D = definePDSScan(
+                                                PDS_CODESCAN_VARIANT_D,false,PDSIntTestProductIdentifier.
+                                                PDS_INTTEST_PRODUCT_CS_SARIF,
+                                                StorageType.REUSE_SECHUB_DATA);
+    
+    public static final TestExecutorConfig PDS_V1_CODE_SCAN_E_DO_NOT_REUSE_SECHUBDATA = definePDSScan(
+                                                PDS_CODESCAN_VARIANT_E,false,
+                                                PDSIntTestProductIdentifier.PDS_INTTEST_PRODUCT_CS_SARIF,
+                                                StorageType.DO_NOT_REUSE_SECHUB_DATA);
+    /* @formatter:on */
     
     public static final String PDS_ENV_VARIABLENAME_TECHUSER_ID="TEST_PDS_TECHUSER_ID";
     public static final String PDS_ENV_VARIABLENAME_TECHUSER_APITOKEN="TEST_PDS_TECHUSER_APITOKEN";
@@ -53,17 +84,13 @@ public class IntegrationTestDefaultExecutorConfigurations {
         return Collections.unmodifiableList(registeredConfigurations);
     }
     
-    private static TestExecutorConfig definePDSScan(String variant, boolean credentialsAsEnvEntries,PDSIntTestProductIdentifier pdsProductIdentifier) {
-        return definePDSScan(variant, credentialsAsEnvEntries, pdsProductIdentifier, true);
-    }
-    
-    private static TestExecutorConfig definePDSScan(String variant, boolean credentialsAsEnvEntries,PDSIntTestProductIdentifier pdsProductIdentifier, boolean useSecHubStorage) {
+    private static TestExecutorConfig definePDSScan(String variant, boolean credentialsAsEnvEntries,PDSIntTestProductIdentifier pdsProductIdentifier, StorageType useSecHubStorage) {
         String productIdentfieriId=pdsProductIdentifier != null ? pdsProductIdentifier.getId():"not-existing";
         return definePDSScan(variant, credentialsAsEnvEntries, productIdentfieriId, useSecHubStorage);
         
     }
     
-    private static TestExecutorConfig definePDSScan(String variant, boolean credentialsAsEnvEntries, String productIdentifierId, boolean useSecHubStorage) {
+    private static TestExecutorConfig definePDSScan(String variant, boolean credentialsAsEnvEntries, String productIdentifierId, StorageType storageType) {
         TestExecutorConfig config = createTestEditorConfig();
         
         config.enabled=true;
@@ -79,6 +106,8 @@ public class IntegrationTestDefaultExecutorConfigurations {
             config.setup.credentials.user=TestAPI.PDS_TECH_USER.getUserId();
             config.setup.credentials.password=TestAPI.PDS_TECH_USER.getApiToken();
         }
+        boolean useSecHubStorage = storageType==StorageType.REUSE_SECHUB_DATA;
+        
         List<TestExecutorSetupJobParam> jobParameters = config.setup.jobParameters;
         jobParameters.add(new TestExecutorSetupJobParam("pds.config.productidentifier",productIdentifierId));
         jobParameters.add(new TestExecutorSetupJobParam("pds.config.use.sechub.storage", Boolean.valueOf(useSecHubStorage).toString()));
diff --git a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/IntegrationTestDefaultProfiles.java b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/IntegrationTestDefaultProfiles.java
index eda7a45eb..2416d2ba9 100644
--- a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/IntegrationTestDefaultProfiles.java
+++ b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/IntegrationTestDefaultProfiles.java
@@ -6,7 +6,7 @@ public class IntegrationTestDefaultProfiles {
     public static final DoNotChangeTestExecutionProfile PROFILE_2_PDS_CODESCAN = defineProfile2();
     public static final DoNotChangeTestExecutionProfile PROFILE_3_PDS_CODESCAN_SARIF = defineProfile3();
     
-    public static final DoNotChangeTestExecutionProfile PROFILE_4_PDS_CODESCAN_SARIF_NO_SECHUB_STORAGE_USED = defineProfile4();
+    public static final DoNotChangeTestExecutionProfile PROFILE_4_NO_STORAGE_REUSED__PDS_CODESCAN_SARIF = defineProfile4();
 
     private static final DoNotChangeTestExecutionProfile[] ALL_PROFILES = new DoNotChangeTestExecutionProfile[] {
 
@@ -16,7 +16,7 @@ public class IntegrationTestDefaultProfiles {
             
             PROFILE_3_PDS_CODESCAN_SARIF,
             
-            PROFILE_4_PDS_CODESCAN_SARIF_NO_SECHUB_STORAGE_USED
+            PROFILE_4_NO_STORAGE_REUSED__PDS_CODESCAN_SARIF
             
     };
 
@@ -57,7 +57,7 @@ public class IntegrationTestDefaultProfiles {
     private static DoNotChangeTestExecutionProfile defineProfile4() {
         
         DoNotChangeTestExecutionProfile profile = new DoNotChangeTestExecutionProfile();
-        profile.initialConfigurationsWithoutUUID.add(IntegrationTestDefaultExecutorConfigurations.PDS_V1_CODE_SCAN_E);
+        profile.initialConfigurationsWithoutUUID.add(IntegrationTestDefaultExecutorConfigurations.PDS_V1_CODE_SCAN_E_DO_NOT_REUSE_SECHUBDATA);
         profile.id = "inttest-default-profile4-sarif"; // not more than 30 chars per profile id, so we use this
         profile.description="Same as profile 3, but executor config does not reuse sechub storage!";
         profile.enabled = true;
diff --git a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/ScenarioInitializer.java b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/ScenarioInitializer.java
index 8064f07e4..f7629a08e 100644
--- a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/ScenarioInitializer.java
+++ b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/internal/ScenarioInitializer.java
@@ -64,7 +64,7 @@ public class ScenarioInitializer {
     }
 	
 	public  ScenarioInitializer ensureDefaultExecutionProfile_4_PDS_codescan_sarif_no_sechub_storage_used() {
-        return ensureDefaultExecutionProfile(IntegrationTestDefaultProfiles.PROFILE_4_PDS_CODESCAN_SARIF_NO_SECHUB_STORAGE_USED);
+        return ensureDefaultExecutionProfile(IntegrationTestDefaultProfiles.PROFILE_4_NO_STORAGE_REUSED__PDS_CODESCAN_SARIF);
     }
 	
 	private  ScenarioInitializer ensureDefaultExecutionProfile(DoNotChangeTestExecutionProfile profile) {
diff --git a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario5/Scenario5.java b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario5/Scenario5.java
index 008bd33de..5823819d7 100644
--- a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario5/Scenario5.java
+++ b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario5/Scenario5.java
@@ -8,11 +8,11 @@ import com.daimler.sechub.integrationtest.internal.CleanScenario;
 import com.daimler.sechub.integrationtest.internal.PDSTestScenario;
 
 /**
- * <b><u>Scenario5 - the PDS integrationtest standard scenario</u></b><br>
+ * <b><u>Scenario5 - the PDS integration test standard scenario. Scenario9 (REUSE SECHUB DATA enabled!)</u></b><br>
  * 
  * In this scenario following is automatically initialized at start (old data
  * removed as well): <br> <br>
- * a) <b> PDS integrationtest configuration is done automatically!</b> 
+ * a) <b> PDS integration test configuration is done automatically!</b> 
  * All configurations from
  * 'sechub-integrationtest/src/main/resources/pds-config-integrationtest.json' will be
  * configured automatically!<br><br>
diff --git a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario6/Scenario6.java b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario6/Scenario6.java
index 4b60c6002..526c0d820 100644
--- a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario6/Scenario6.java
+++ b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario6/Scenario6.java
@@ -6,7 +6,7 @@ import com.daimler.sechub.integrationtest.internal.PDSTestScenario;
 import com.daimler.sechub.integrationtest.internal.StaticTestScenario;
 
 /**
- * <b><u>Scenario6 - the PDS ONLY integration test scenario</u></b><br>
+ * <b><u>Scenario6 - the PDS ONLY integration test scenario (no special sechub storage setings necessary)</u></b><br>
  * 
  * In this scenario no sechub server instance is necessary. No special
  * preparations are done.
diff --git a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario9/Scenario9.java b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario9/Scenario9.java
index 707db8b09..4d4b7c471 100644
--- a/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario9/Scenario9.java
+++ b/sechub-integrationtest/src/main/java/com/daimler/sechub/integrationtest/scenario9/Scenario9.java
@@ -8,11 +8,11 @@ import com.daimler.sechub.integrationtest.internal.CleanScenario;
 import com.daimler.sechub.integrationtest.internal.PDSTestScenario;
 
 /**
- * <b><u>Scenario9 - the PDS integrationtest SARIF scenario (REUSE SECHUB DATA enabled!)</u></b><br>
+ * <b><u>Scenario9 - the PDS integration test SARIF scenario (REUSE SECHUB DATA enabled!)</u></b><br>
  * 
  * In this scenario following is automatically initialized at start (old data
  * removed as well): <br> <br>
- * a) <b> PDS integrationtest configuration is done automatically!</b> 
+ * a) <b> PDS integration test configuration is done automatically!</b> 
  * All configurations from
  * 'sechub-integrationtest/src/main/resources/pds-config-integrationtest.json' will be
  * configured automatically!<br><br>
diff --git a/sechub-integrationtest/src/test/java/com/daimler/sechub/integrationtest/scenario5/PDSCodeScanJobScenario5IntTest.java b/sechub-integrationtest/src/test/java/com/daimler/sechub/integrationtest/scenario5/PDSCodeScanJobScenario5IntTest.java
index d9b6f9a92..7f96ef47a 100644
--- a/sechub-integrationtest/src/test/java/com/daimler/sechub/integrationtest/scenario5/PDSCodeScanJobScenario5IntTest.java
+++ b/sechub-integrationtest/src/test/java/com/daimler/sechub/integrationtest/scenario5/PDSCodeScanJobScenario5IntTest.java
@@ -39,7 +39,7 @@ public class PDSCodeScanJobScenario5IntTest {
 
     @SuppressWarnings("deprecation") // we use assertSecHubReport here - old implementation okay here
     @Test
-    public void a_user_can_start_a_pds_scan_job_and_gets_result_containing_expected_findings_and_also_dynamic_parts() {
+    public void pds_reuse_sechub_data__a_user_can_start_a_pds_scan_job_and_gets_result_containing_expected_findings_and_also_dynamic_parts() {
         /* @formatter:off */
 
         /* prepare */
diff --git a/sechub-pds/src/main/java/com/daimler/sechub/pds/batch/PDSBatchTriggerService.java b/sechub-pds/src/main/java/com/daimler/sechub/pds/batch/PDSBatchTriggerService.java
index 66b51a037..84d1c01f9 100644
--- a/sechub-pds/src/main/java/com/daimler/sechub/pds/batch/PDSBatchTriggerService.java
+++ b/sechub-pds/src/main/java/com/daimler/sechub/pds/batch/PDSBatchTriggerService.java
@@ -1,7 +1,8 @@
 // SPDX-License-Identifier: MIT
 package com.daimler.sechub.pds.batch;
 
-import java.util.Optional;
+import java.util.Random;
+import java.util.UUID;
 
 import javax.annotation.PostConstruct;
 
@@ -9,15 +10,14 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.orm.ObjectOptimisticLockingFailureException;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
 import com.daimler.sechub.pds.PDSMustBeDocumented;
 import com.daimler.sechub.pds.execution.PDSExecutionService;
-import com.daimler.sechub.pds.job.PDSJob;
 import com.daimler.sechub.pds.job.PDSJobRepository;
-import com.daimler.sechub.pds.job.PDSJobStatusState;
+import com.daimler.sechub.pds.job.PDSJobTransactionService;
 
 @Service
 public class PDSBatchTriggerService {
@@ -35,17 +35,20 @@ public class PDSBatchTriggerService {
     @Autowired
     PDSJobRepository repository;
 
-    @PDSMustBeDocumented(value="initial delay for next job trigger in milliseconds",scope="scheduler")
+    @Autowired
+    PDSJobTransactionService jobTransactionService;
+
+    @PDSMustBeDocumented(value = "initial delay for next job trigger in milliseconds", scope = "scheduler")
     @Value("${sechub.pds.config.trigger.nextjob.initialdelay:" + DEFAULT_INITIAL_DELAY_MILLIS + "}")
     private String infoInitialDelay; // here only for logging - used in scheduler annotation as well!
 
-    @PDSMustBeDocumented(value="delay for next job trigger in milliseconds",scope="scheduler")
+    @PDSMustBeDocumented(value = "delay for next job trigger in milliseconds", scope = "scheduler")
     @Value("${sechub.pds.config.trigger.nextjob.delay:" + DEFAULT_FIXED_DELAY_MILLIS + "}")
     private String infoFixedDelay; // here only for logging - used in scheduler annotation as well!
 
-    @PDSMustBeDocumented(value="Set scheduler enabled state",scope="scheduler")
-    @Value("${sechub.pds.config.scheduling.enable:"+DEFAULT_SCHEDULING_ENABLED+"}")
-    boolean schedulingEnabled=DEFAULT_SCHEDULING_ENABLED;
+    @PDSMustBeDocumented(value = "Set scheduler enabled state", scope = "scheduler")
+    @Value("${sechub.pds.config.scheduling.enable:" + DEFAULT_SCHEDULING_ENABLED + "}")
+    boolean schedulingEnabled = DEFAULT_SCHEDULING_ENABLED;
 
     @PostConstruct
     protected void postConstruct() {
@@ -56,7 +59,6 @@ public class PDSBatchTriggerService {
     // default 10 seconds delay and 5 seconds initial
     @Scheduled(initialDelayString = "${sechub.pds.config.trigger.nextjob.initialdelay:" + DEFAULT_INITIAL_DELAY_MILLIS
             + "}", fixedDelayString = "${sechub.pds.config.trigger.nextjob.delay:" + DEFAULT_FIXED_DELAY_MILLIS + "}")
-    @Transactional
     public void triggerExecutionOfNextJob() {
         if (!schedulingEnabled) {
             LOG.trace("Trigger execution of next job canceled, because scheduling disabled.");
@@ -67,21 +69,44 @@ public class PDSBatchTriggerService {
             LOG.debug("Execution service is not able to execute next job, so cancel here");
             return;
         }
-        /* query does auto increment version here! */
-        Optional<PDSJob> nextJob = repository.findNextJobToExecute();
-        if (!nextJob.isPresent()) {
-            LOG.trace("No next job present");
-            return;
-        }
-        PDSJob pdsJob = nextJob.get();
-        pdsJob.setState(PDSJobStatusState.QUEUED);
-
         /*
-         * next is done async - so on leave of this methods PDS job version will be
-         * updated + state set to queue, so no other POD will process this job again
+         * find next job and mark it as already queued - so no other PDS instance does
+         * try to process it
          */
-        executionService.addToExecutionQueueAsynchron(pdsJob.getUUID());
+        UUID uuid = null;
+
+        boolean fetchedNextJob = false;
+        while (!fetchedNextJob) {
+
+            try {
+                uuid = jobTransactionService.findNextJobToExecuteAndMarkAsQueued();
+
+                fetchedNextJob = true;
+
+            } catch (ObjectOptimisticLockingFailureException e) {
+                /*
+                 * This can happen when PDS instances are started at same time, so the check for
+                 * next jobs can lead to race condiitons - and optmistic locks will occurre
+                 * here.
+                 * 
+                 * To avoid this to happen again, we wait a random time here. So next call on
+                 * this machine should normally not collide again.
+                 */
+                Random random = new Random();
+                int millis = random.ints(50, 3000).findFirst().getAsInt();
+                LOG.info("Next job was already handled by another cluster member - will wait {} milliseconds and retry.", millis);
+                try {
+                    Thread.sleep(millis);
+                } catch (InterruptedException e1) {
+                    Thread.currentThread().interrupt();
+                }
+                LOG.info("Wait done - try again");
+            }
+        }
+        if (uuid == null) {
+            return;
+        }
+        executionService.addToExecutionQueueAsynchron(uuid);
 
     }
-
 }
\\ No newline at end of file
diff --git a/sechub-pds/src/main/java/com/daimler/sechub/pds/execution/PDSExecutionCallable.java b/sechub-pds/src/main/java/com/daimler/sechub/pds/execution/PDSExecutionCallable.java
index bb5053b98..6a0d5be0b 100644
--- a/sechub-pds/src/main/java/com/daimler/sechub/pds/execution/PDSExecutionCallable.java
+++ b/sechub-pds/src/main/java/com/daimler/sechub/pds/execution/PDSExecutionCallable.java
@@ -16,7 +16,6 @@ import java.util.concurrent.TimeUnit;
 import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.orm.ObjectOptimisticLockingFailureException;
 
 import com.daimler.sechub.pds.PDSJSONConverterException;
 import com.daimler.sechub.pds.job.PDSJobConfiguration;
@@ -35,7 +34,6 @@ import com.daimler.sechub.pds.usecase.UseCaseUserCancelsJob;
 class PDSExecutionCallable implements Callable<PDSExecutionResult> {
 
     private static final Logger LOG = LoggerFactory.getLogger(PDSExecutionCallable.class);
-    private static final int MAXIMUM_RETRIES_ON_OPTIMISTIC_LOCKS = 2;
 
     private PDSJobTransactionService jobTransactionService;
     private Process process;
@@ -64,7 +62,7 @@ class PDSExecutionCallable implements Callable<PDSExecutionResult> {
         PDSExecutionResult result = new PDSExecutionResult();
         PDSJobConfiguration config = null;
         try {
-            updateWithRetriesOnOptimisticLocks(UpdateState.RUNNING);
+            jobTransactionService.markJobAsRunningInOwnTransaction(jobUUID);
 
             String configJSON = jobTransactionService.getJobConfiguration(jobUUID);
 
@@ -103,32 +101,6 @@ class PDSExecutionCallable implements Callable<PDSExecutionResult> {
         return result;
     }
 
-    private enum UpdateState {
-        RUNNING,
-    }
-
-    private void updateWithRetriesOnOptimisticLocks(UpdateState state) {
-
-        int retries = 0;
-        while (true) {
-            try {
-                if (state == UpdateState.RUNNING) {
-                    jobTransactionService.markJobAsRunningInOwnTransaction(jobUUID);
-                }
-                break;
-
-            } catch (ObjectOptimisticLockingFailureException e) {
-
-                /* we just retry - to avoid any optimistic locks */
-                if (retries > MAXIMUM_RETRIES_ON_OPTIMISTIC_LOCKS) {
-                    throw new IllegalStateException("Still having optimistic lock problems - event after " + retries + " retries", e);
-                }
-                retries++;
-                LOG.info("Had optimistic lock problem on update for job {} - do retry nr.{}", jobUUID, retries);
-            }
-        }
-    }
-
     private void waitForProcessEndAndGetResultByFiles(PDSExecutionResult result, UUID jobUUID, PDSJobConfiguration config, long minutesToWaitForResult)
             throws InterruptedException, IOException {
         LOG.debug("Wait for process of job with uuid:{}, will wait {} minutes for result from product with id:{}", jobUUID, minutesToWaitForResult,
diff --git a/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobRepositoryCustom.java b/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobRepositoryCustom.java
index d99686249..50a2d4a90 100644
--- a/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobRepositoryCustom.java
+++ b/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobRepositoryCustom.java
@@ -5,10 +5,6 @@ import java.util.Optional;
 
 public interface PDSJobRepositoryCustom {
 
-	/**
-	 * @return next executable job as optional - check if present or not is
-	 *         necessary
-	 */
 	Optional<PDSJob> findNextJobToExecute();
 	
 	long countJobsOfServerInState(String serverId, PDSJobStatusState state);
diff --git a/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobRepositoryImpl.java b/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobRepositoryImpl.java
index 3ff1d2882..da457cbbc 100644
--- a/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobRepositoryImpl.java
+++ b/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobRepositoryImpl.java
@@ -46,7 +46,7 @@ public class PDSJobRepositoryImpl implements PDSJobRepositoryCustom {
         query.setParameter(PROPERTY_STATE, READY_TO_START);
         query.setMaxResults(1);
         // we use OPTIMISTIC_FORCE_INCREMENT write lock - so only one POD will be able
-        // to execute next job...
+        // to execute next job... (it's just a fuse, it should not happen)
         // see https://www.baeldung.com/jpa-pessimistic-locking
         query.setLockMode(LockModeType.OPTIMISTIC_FORCE_INCREMENT);
 
diff --git a/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobTransactionService.java b/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobTransactionService.java
index 0936b5f83..e5ca1620b 100644
--- a/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobTransactionService.java
+++ b/sechub-pds/src/main/java/com/daimler/sechub/pds/job/PDSJobTransactionService.java
@@ -5,6 +5,7 @@ import static com.daimler.sechub.pds.job.PDSJobAssert.*;
 import static com.daimler.sechub.pds.util.PDSAssert.*;
 
 import java.time.LocalDateTime;
+import java.util.Optional;
 import java.util.UUID;
 
 import javax.annotation.security.RolesAllowed;
@@ -28,10 +29,13 @@ public class PDSJobTransactionService {
     PDSJobRepository repository;
 
     public PDSJobTransactionService() {
-        //
     }
 
-    /* mark as running - no matter of state before */
+    /**
+     * Mark job as ready to start - state before allowed: only CREATED
+     * 
+     * @param jobUUID
+     */
     @RolesAllowed({ PDSRoleConstants.ROLE_USER, PDSRoleConstants.ROLE_SUPERADMIN })
     public void markReadyToStartInOwnTransaction(UUID jobUUID) {
         LOG.info("Mark job {} as ready to start", jobUUID);
@@ -39,18 +43,18 @@ public class PDSJobTransactionService {
     }
 
     /**
-     * Marks job as running - no matter which state before
+     * Mark job as running - no matter which state before
      * 
-     * @param uuid
+     * @param jobUUID
      */
-    public void markJobAsRunningInOwnTransaction(UUID uuid) {
-        updateJobInOwnTransaction(uuid, null, LocalDateTime.now(), null, PDSJobStatusState.RUNNING, PDSJobStatusState.values());
+    public void markJobAsRunningInOwnTransaction(UUID jobUUID) {
+        updateJobInOwnTransaction(jobUUID, null, LocalDateTime.now(), null, PDSJobStatusState.RUNNING, PDSJobStatusState.values());
     }
 
     private void updateJobInOwnTransaction(UUID jobUUID, String result, LocalDateTime started, LocalDateTime ended, PDSJobStatusState newState,
             PDSJobStatusState... acceptedStatesBefore) {
         notNull(jobUUID, "job uuid may not be null!");
-        
+
         PDSJob job = assertJobFound(jobUUID, repository);
         if (started != null) {
             job.setStarted(started);
@@ -66,7 +70,29 @@ public class PDSJobTransactionService {
         LOG.debug("Updated job in own transaction - pds job uuid={}, state={}", job.getUUID(), job.getState());
     }
 
+    /**
+     * Read job configuration in own transaction
+     * 
+     * @param jobUUID
+     * @return job configuration, will fail when job is not found
+     */
     public String getJobConfiguration(UUID jobUUID) {
         return assertJobFound(jobUUID, repository).getJsonConfiguration();
     }
+
+    /**
+     * Resolves next job to execute. If found the job will be marked as queued
+     * 
+     * @return uuid or <code>null</code> if no job found to put in queue.
+     */
+    public UUID findNextJobToExecuteAndMarkAsQueued() {
+        
+        Optional<PDSJob> nextJob = repository.findNextJobToExecute();
+        if (!nextJob.isPresent()) {
+            return null;
+        }
+        PDSJob pdsJob = nextJob.get();
+        pdsJob.setState(PDSJobStatusState.QUEUED);
+        return pdsJob.getUUID();
+    }
 }
diff --git a/sechub-pds/src/test/java/com/daimler/sechub/pds/batch/PDSBatchTriggerServiceTest.java b/sechub-pds/src/test/java/com/daimler/sechub/pds/batch/PDSBatchTriggerServiceTest.java
index 59ab34aa1..81f9ee5aa 100644
--- a/sechub-pds/src/test/java/com/daimler/sechub/pds/batch/PDSBatchTriggerServiceTest.java
+++ b/sechub-pds/src/test/java/com/daimler/sechub/pds/batch/PDSBatchTriggerServiceTest.java
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: MIT
 package com.daimler.sechub.pds.batch;
 
-import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
 import java.util.Optional;
@@ -13,91 +13,83 @@ import org.junit.Test;
 import com.daimler.sechub.pds.execution.PDSExecutionService;
 import com.daimler.sechub.pds.job.PDSJob;
 import com.daimler.sechub.pds.job.PDSJobRepository;
-import com.daimler.sechub.pds.job.PDSJobStatusState;
+import com.daimler.sechub.pds.job.PDSJobTransactionService;
 
 public class PDSBatchTriggerServiceTest {
 
     private PDSBatchTriggerService serviceToTest;
     private PDSExecutionService executionService;
     private PDSJobRepository repository;
+    private PDSJobTransactionService jobTransactionService;
+    private UUID nextJobUUID;
+    private PDSJob job;
 
     @Before
     public void before() throws Exception {
+        nextJobUUID = UUID.randomUUID();
+        job = mock(PDSJob.class);
+        when(job.getUUID()).thenReturn(nextJobUUID);
+
         executionService = mock(PDSExecutionService.class);
         repository = mock(PDSJobRepository.class);
+        jobTransactionService = mock(PDSJobTransactionService.class);
+        when(jobTransactionService.findNextJobToExecuteAndMarkAsQueued()).thenReturn(nextJobUUID);
 
         serviceToTest = new PDSBatchTriggerService();
 
         serviceToTest.executionService = executionService;
         serviceToTest.repository = repository;
+        serviceToTest.jobTransactionService = jobTransactionService;
     }
 
     @Test
-    public void a_job_found_for_next_execution_is_changed_to_state_QUEUED() {
+    public void a_job_found_for_next_execution_executor_service_called() {
         /* prepare */
-        PDSJob job = new PDSJob();
-        job.setState(PDSJobStatusState.READY_TO_START);
-
         when(repository.findNextJobToExecute()).thenReturn(Optional.of(job));
 
-        /* check precondition */
-        assertEquals(PDSJobStatusState.READY_TO_START, job.getState());
-
         /* execute */
         serviceToTest.triggerExecutionOfNextJob();
 
         /* test */
-        assertEquals(PDSJobStatusState.QUEUED, job.getState());
+        verify(executionService).addToExecutionQueueAsynchron(nextJobUUID);
     }
-    
+
     @Test
-    public void a_job_found_for_next_execution_but_scheduling_disabled_job_is_not_changed() {
+    public void a_job_found_for_next_execution_jobtransaction_service_is_called() {
         /* prepare */
-        serviceToTest.schedulingEnabled=false;
-        PDSJob job = new PDSJob();
-        job.setState(PDSJobStatusState.READY_TO_START);
-
         when(repository.findNextJobToExecute()).thenReturn(Optional.of(job));
 
-        /* check precondition */
-        assertEquals(PDSJobStatusState.READY_TO_START, job.getState());
-
         /* execute */
         serviceToTest.triggerExecutionOfNextJob();
 
         /* test */
-        assertEquals(PDSJobStatusState.READY_TO_START, job.getState());
+        verify(jobTransactionService).findNextJobToExecuteAndMarkAsQueued();
     }
-    
+
     @Test
-    public void a_job_found_for_next_execution_but_scheduling_disabled_executor_service_not_called() {
+    public void a_job_found_for_next_execution_but_scheduling_disabled_executor_service_is_NOT_called() {
         /* prepare */
-        serviceToTest.schedulingEnabled=false;
-        UUID uuid = UUID.randomUUID();
-        PDSJob job = mock(PDSJob.class);
-        when(job.getUUID()).thenReturn(uuid);
+        serviceToTest.schedulingEnabled = false;
         when(repository.findNextJobToExecute()).thenReturn(Optional.of(job));
-        
+
         /* execute */
         serviceToTest.triggerExecutionOfNextJob();
-        
+
         /* test */
-        verify(executionService,never()).addToExecutionQueueAsynchron(uuid);
+        verify(executionService, never()).addToExecutionQueueAsynchron(any());
     }
-    
+
     @Test
-    public void a_job_found_for_next_execution_executor_service_called() {
+    public void a_job_found_for_next_execution_but_scheduling_disabled_jobtransaction_service_is_NOT_called() {
         /* prepare */
-        UUID uuid = UUID.randomUUID();
-        PDSJob job = mock(PDSJob.class);
-        when(job.getUUID()).thenReturn(uuid);
+        serviceToTest.schedulingEnabled = false;
         when(repository.findNextJobToExecute()).thenReturn(Optional.of(job));
-        
+
         /* execute */
         serviceToTest.triggerExecutionOfNextJob();
-        
+
         /* test */
-        verify(executionService).addToExecutionQueueAsynchron(uuid);
+        verify(jobTransactionService, never()).findNextJobToExecuteAndMarkAsQueued();
     }
 
 }