Skip to content

Commit

Permalink
chore(merge): release-10.2.0 into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
bonita-ci committed Sep 12, 2024
2 parents 3aaf7a1 + fc4c73f commit 3e59df0
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
import org.assertj.core.api.Assertions;
import org.bonitasoft.engine.CommonAPIIT;
import org.bonitasoft.engine.PrintTestsStatusRule;
import org.bonitasoft.engine.api.*;
import org.bonitasoft.engine.api.APIClient;
import org.bonitasoft.engine.api.IdentityAPI;
import org.bonitasoft.engine.api.LoginAPI;
import org.bonitasoft.engine.api.PlatformAPI;
import org.bonitasoft.engine.api.PlatformAPIAccessor;
import org.bonitasoft.engine.api.TenantAPIAccessor;
import org.bonitasoft.engine.bpm.flownode.TimerType;
import org.bonitasoft.engine.bpm.process.ProcessDefinition;
import org.bonitasoft.engine.bpm.process.impl.ProcessDefinitionBuilder;
Expand Down Expand Up @@ -137,7 +142,7 @@ public void should_have_processes_with_duration_timer_still_work_after_restart()
apiClient.getProcessAPI().startProcess(wait2Sec.getId());
}

Thread.sleep(800);
await().until(() -> apiClient.getProcessAPI().getNumberOfProcessInstances(), nb -> nb > 0L);
Assertions.assertThat(apiClient.getProcessAPI().getNumberOfProcessInstances()).isGreaterThan(0);
restartPlatform();
apiClient.login("install", "install");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

<!-- Show stack traces when there is error on jobs -->
<!-- <logger name="org.bonitasoft.engine.scheduler.impl.JobWrapper" level="DEBUG" /> -->
<logger name="org.bonitasoft.engine.scheduler.impl.QuartzSchedulerExecutor" level="DEBUG" />

<!-- Show lock acquire/release -->
<!--<logger name="org.bonitasoft.engine.execution.work.FailureHandlingBonitaWork" level="TRACE" />-->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@
**/
package org.bonitasoft.engine.job;

import static java.util.Collections.emptyMap;
import static java.util.Collections.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.junit.Assert.assertEquals;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
Expand Down Expand Up @@ -80,65 +78,51 @@ public void retryAJob_should_execute_again_a_failed_job_and_clean_related_job_lo
assertThat(failedJob.getNumberOfFailures()).isEqualTo(1);
assertThat(failedJob.getDescription()).isEqualTo("Throw an exception when 'throwException'=true");

final List<SJobDescriptor> jobDescriptors = searchJobDescriptors(1);
final long jobDescriptorId = jobDescriptors.get(0).getId();
try {
searchJobLogs(jobDescriptorId, 1);
} catch (final AssertionError e) {
Thread.sleep(800);
searchJobLogs(jobDescriptorId, 1);
}
final List<SJobDescriptor> jobDescriptors = waitForJobDescriptorsToHaveSize(1);
waitForJobLogsToHaveSize(jobDescriptors.get(0).getId(), 1);

//when
getProcessAPI().replayFailedJob(failedJob.getJobDescriptorId(),
Collections.singletonMap("throwException", Boolean.FALSE));
singletonMap("throwException", Boolean.FALSE));

//then
assertJobWasExecutedWithSuccess();

try {
searchJobDescriptors(0);
} catch (final AssertionError e) {
Thread.sleep(800);
searchJobDescriptors(0);
}
searchJobLogs(jobDescriptorId, 0);
waitForJobDescriptorsToHaveSize(0);
waitForJobLogsToHaveSize(jobDescriptors.get(0).getId(), 0);

// clean up:
deleteJobLogsAndDescriptors(failedJob.getJobDescriptorId());
} finally {
getCommandAPI().unregister("except");
}
}

private void searchJobLogs(final long jobDescriptorId, final int nbOfExpectedJobLogs) throws Exception {
setSessionInfo(getSession()); // the session was cleaned by api call. This must be improved
final ServiceAccessor serviceAccessor = getServiceAccessor();
final UserTransactionService transactionService = serviceAccessor.getUserTransactionService();
final JobService jobService = serviceAccessor.getJobService();

private void waitForJobLogsToHaveSize(final long jobDescriptorId, final int nbOfExpectedJobLogs) {
final QueryOptions options = new QueryOptions(0, 1, null,
Collections.singletonList(new FilterOption(SJobLog.class, "jobDescriptorId", jobDescriptorId)), null);

final Callable<List<SJobLog>> searchJobLogs = () -> jobService.searchJobLogs(options);
final List<SJobLog> jobLogs = transactionService.executeInTransaction(searchJobLogs);
assertEquals(nbOfExpectedJobLogs, jobLogs.size());
singletonList(new FilterOption(SJobLog.class, "jobDescriptorId", jobDescriptorId)), null);

await().until(() -> {
setSessionInfo(getSession()); // the session was cleaned by api call. This must be improved
final ServiceAccessor serviceAccessor = getServiceAccessor();
final UserTransactionService transactionService = serviceAccessor.getUserTransactionService();
final JobService jobService = serviceAccessor.getJobService();
return transactionService.executeInTransaction(() -> jobService.searchJobLogs(options));
}, hasSize(nbOfExpectedJobLogs));
}

private List<SJobDescriptor> searchJobDescriptors(final int nbOfExpectedJobDescriptors) throws Exception {
setSessionInfo(getSession()); // the session was cleaned by api call. This must be improved
final ServiceAccessor serviceAccessor = getServiceAccessor();
final JobService jobService = serviceAccessor.getJobService();
final UserTransactionService transactionService = serviceAccessor.getUserTransactionService();

final List<FilterOption> filters = Collections
.singletonList(
new FilterOption(SJobDescriptor.class, "jobClassName", ThrowsExceptionJob.class.getName()));
private List<SJobDescriptor> waitForJobDescriptorsToHaveSize(final int nbOfExpectedJobDescriptors) {
final List<FilterOption> filters = singletonList(
new FilterOption(SJobDescriptor.class, "jobClassName", ThrowsExceptionJob.class.getName()));
final QueryOptions queryOptions = new QueryOptions(0, 1, null, filters, null);

final Callable<List<SJobDescriptor>> searchJobLogs = () -> jobService.searchJobDescriptors(queryOptions);
final List<SJobDescriptor> jobDescriptors = transactionService.executeInTransaction(searchJobLogs);

assertEquals(nbOfExpectedJobDescriptors, jobDescriptors.size());
return jobDescriptors;
return await().until(() -> {
setSessionInfo(getSession()); // the session was cleaned by api call. This must be improved
final ServiceAccessor serviceAccessor = getServiceAccessor();
final UserTransactionService transactionService = serviceAccessor.getUserTransactionService();
final JobService jobService = serviceAccessor.getJobService();
return transactionService.executeInTransaction(() -> jobService.searchJobDescriptors(queryOptions));
}, hasSize(nbOfExpectedJobDescriptors));
}

@Test
Expand All @@ -159,11 +143,25 @@ public void retryAJob_should_update_job_log_when_execution_fails_again() throws
assertThat(failedJob.getLastMessage()).contains(
"org.bonitasoft.engine.scheduler.exception.SJobExecutionException: This job throws an arbitrary exception");
assertThat(failedJob.getNumberOfFailures()).isEqualTo(1);

deleteJobLogsAndDescriptors(failedJob.getJobDescriptorId());
} finally {
getCommandAPI().unregister("except");
}
}

private void deleteJobLogsAndDescriptors(final long jobDescriptorId) throws Exception {
setSessionInfo(getSession()); // the session was cleaned by api call. This must be improved
final ServiceAccessor serviceAccessor = getServiceAccessor();
final UserTransactionService transactionService = serviceAccessor.getUserTransactionService();
final JobService jobService = serviceAccessor.getJobService();
transactionService.executeInTransaction((Callable) () -> {
jobService.deleteJobLogs(jobDescriptorId);
jobService.deleteJobDescriptor(jobDescriptorId);
return null;
});
}

private FailedJob waitForFailedJob() throws Exception {
new WaitUntil(DEFAULT_REPEAT_EACH, DEFAULT_TIMEOUT) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public void setAttributes(Map<String, Serializable> attributes) {

@Override
public void execute() throws SJobExecutionException {
System.err.println(
"Executing job:"
+ failOnce + ", "
+ failOnceWithRetryable + ", "
+ throwsError + ", "
+ throwsJobExecutionException);
if (failOnce) {
if (variableStorage.getVariableValue("nbJobException", 0) == 0) {
variableStorage.setVariable("nbJobException", 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.awaitility.Durations.FIVE_HUNDRED_MILLISECONDS;
import static org.bonitasoft.engine.scheduler.impl.JobThatMayThrowErrorOrJobException.*;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.junit.Assert.*;
Expand All @@ -28,6 +29,7 @@
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

import org.awaitility.core.ConditionTimeoutException;
import org.bonitasoft.engine.bpm.CommonBPMServicesTest;
import org.bonitasoft.engine.persistence.QueryOptions;
import org.bonitasoft.engine.scheduler.JobService;
Expand Down Expand Up @@ -113,7 +115,7 @@ public void doNotThrowAnExceptionWhenDeletingAnUnknownJob() throws Exception {

/*
* We must ensure that:
* * pause only jobs of the current tenant
* * pause jobs
* * trigger new job are not executed
* * resume the jobs resume it really
* *
Expand Down Expand Up @@ -159,25 +161,39 @@ public void should_be_able_to_list_job_that_failed_because_of_an_Error() throws
public void should_be_able_to_restart_a_job_that_failed_because_of_a_SJobExecutionException() throws Exception {
// schedule a job that throws a SJobExecutionException
schedule(jobDescriptor(JobThatMayThrowErrorOrJobException.class, "MyJob"),
new OneShotTrigger("triggerJob", new Date(System.currentTimeMillis() + 100)),
new OneShotTrigger("triggerJob", new Date(System.currentTimeMillis() + 10)),
singletonMap(TYPE, JOBEXCEPTION));
SJobDescriptor persistedJobDescriptor = getFirstPersistedJob();

//we have failed job
List<SFailedJob> failedJobs = await().until(() -> inTx(() -> jobService.getFailedJobs(0, 100)), hasSize(1));
assertThat(failedJobs)
.hasOnlyOneElementSatisfying(f -> assertThat(f.getLastMessage()).contains("a Job exception"));
List<SFailedJob> failedJobs = await().until(() -> inTx(() -> jobService.getFailedJobs(0, 3)), hasSize(1));
assertThat(failedJobs.get(0).getLastMessage()).contains("a Job exception");

//small sleep because quartz do not always immediately delete the associated trigger (done in the quartz Thread)
// because of that it can cause issues when rescheduling (Foreign key violation)
Thread.sleep(500);
//reschedule the job: no more exception
inTx(() -> {
schedulerService.retryJobThatFailed(persistedJobDescriptor.getId(),
toJobParameterList(singletonMap(TYPE, NO_EXCEPTION)));
return null;
});
await().until(() -> storage.getVariableValue("nbSuccess", 0).equals(1));
// small sleep because quartz does not always immediately delete the associated trigger (done in the quartz Thread)
// because of that, it can cause issues when rescheduling (Foreign key violation)
Thread.sleep(100);
// reschedule the job: should be no more exception
try {
inTx(() -> {
schedulerService.retryJobThatFailed(persistedJobDescriptor.getId(),
toJobParameterList(singletonMap(TYPE, NO_EXCEPTION)));
return null;
});
// System.err.println("nbSuccess: " + storage.getVariableValue("nbSuccess"));
await().pollDelay(FIVE_HUNDRED_MILLISECONDS)
.until(() -> storage.getVariableValue("nbSuccess", 0).equals(1));
} catch (ConditionTimeoutException e) {
// System.err.println("nbSuccess: " + storage.getVariableValue("nbSuccess"));
System.err.println("retrying to reschedule failed job");
inTx(() -> {
schedulerService.retryJobThatFailed(persistedJobDescriptor.getId(),
toJobParameterList(singletonMap(TYPE, NO_EXCEPTION)));
return null;
});
await().pollDelay(FIVE_HUNDRED_MILLISECONDS)
.until(() -> storage.getVariableValue("nbSuccess", 0).equals(1));
System.err.println("Yes, retrying the job later solved the problem!");
}
}

@Test
Expand All @@ -199,7 +215,7 @@ public void should_be_able_to_restart_a_cron_job_that_failed_because_of_a_SJobEx
throw new RuntimeException(e);
}
};
List<SFailedJob> sFailedJobs = await().until(getFailedJobs, new BaseMatcher<List<SFailedJob>>() {
List<SFailedJob> sFailedJobs = await().until(getFailedJobs, new BaseMatcher<>() {

@Override
public boolean matches(Object item) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void setAttributes(final Map<String, Serializable> attributes) {
}

/*
* create a new semphore and wait for the release to be called
* create a new semaphore and wait for the release to be called
*/
public static void waitForJobToExecuteOnce() throws Exception {
semaphore = new JobSemaphore(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@
public class VariableStorage implements Serializable {

private static final long serialVersionUID = -4195221111626812999L;

private final Object lock = new Object();
private final Map<String, Object> variables;
public static final VariableStorage INSTANCE = new VariableStorage();

private VariableStorage() {
variables = new HashMap<String, Object>();
variables = new HashMap<>();
}

public static VariableStorage getInstance() {
Expand Down

0 comments on commit 3e59df0

Please sign in to comment.