use of org.springframework.transaction.support.TransactionCallback in project gocd by gocd.
the class ScheduleService method scheduleStage.
public Stage scheduleStage(final Pipeline pipeline, final String stageName, final String username, final StageInstanceCreator creator, final ErrorConditionHandler errorHandler) {
return (Stage) transactionTemplate.execute((TransactionCallback) status -> {
String pipelineName = pipeline.getName();
PipelineConfig pipelineConfig = goConfigService.pipelineConfigNamed(new CaseInsensitiveString(pipelineName));
StageConfig stageConfig = pipelineConfig.findBy(new CaseInsensitiveString(stageName));
if (stageConfig == null) {
throw new StageNotFoundException(pipelineName, stageName);
}
SchedulingContext context = schedulingContext(username, pipelineConfig, stageConfig);
pipelineLockService.lockIfNeeded(pipeline);
Stage instance = null;
try {
instance = creator.create(pipelineName, stageName, context);
LOGGER.info("[Stage Schedule] Scheduling stage {} for pipeline {}", stageName, pipeline.getName());
} catch (CannotScheduleException e) {
serverHealthService.update(stageSchedulingFailedState(pipelineName, e));
errorHandler.cantSchedule(e, pipelineName);
}
serverHealthService.update(stageSchedulingSuccessfulState(pipelineName, stageName));
stageService.save(pipeline, instance);
return instance;
});
}
use of org.springframework.transaction.support.TransactionCallback in project gocd by gocd.
the class PipelineScheduleQueue method createPipeline.
public Pipeline createPipeline(final BuildCause buildCause, final PipelineConfig pipelineConfig, final SchedulingContext context, final String md5, final Clock clock) {
return (Pipeline) transactionTemplate.execute((TransactionCallback) status -> {
Pipeline pipeline = null;
if (shouldCancel(buildCause, pipelineConfig.name())) {
LOGGER.debug("[Pipeline Schedule] Cancelling scheduling as build cause {} is the same as the most recent schedule", buildCause);
cancelSchedule(pipelineConfig.name());
} else {
try {
Pipeline newPipeline = instanceFactory.createPipelineInstance(pipelineConfig, buildCause, context, md5, clock);
pipeline = pipelineService.save(newPipeline);
finishSchedule(pipelineConfig.name(), buildCause, pipeline.getBuildCause());
LOGGER.debug("[Pipeline Schedule] Successfully scheduled pipeline {}, buildCause:{}, configOrigin: {}", pipelineConfig.name(), buildCause, pipelineConfig.getOrigin());
} catch (BuildCauseOutOfDateException e) {
cancelSchedule(pipelineConfig.name());
LOGGER.info("[Pipeline Schedule] Build cause {} is out of date. Scheduling is cancelled. Go will reschedule this pipeline. configOrigin: {}", buildCause, pipelineConfig.getOrigin());
}
}
return pipeline;
});
}
use of org.springframework.transaction.support.TransactionCallback in project gocd by gocd.
the class PackageMaterialUpdaterTest method setup.
@BeforeEach
public void setup() {
transactionTemplate = new TransactionTemplate(null) {
@Override
public Object execute(TransactionCallback action) {
return action.doInTransaction(null);
}
@Override
public Object executeWithExceptionHandling(com.thoughtworks.go.server.transaction.TransactionCallback action) throws Exception {
// To change body of overridden methods use File | Settings | File Templates.
return super.executeWithExceptionHandling(action);
}
@Override
public <T extends Exception> Object transactionSurrounding(TransactionSurrounding<T> surrounding) throws T {
// To change body of overridden methods use File | Settings | File Templates.
return super.transactionSurrounding(surrounding);
}
};
materialUpdater = new PackageMaterialUpdater(materialRepository, scmMaterialUpdater, transactionTemplate);
}
use of org.springframework.transaction.support.TransactionCallback in project gocd by gocd.
the class PluggableSCMMaterialUpdaterTest method setup.
@BeforeEach
public void setup() {
transactionTemplate = new TransactionTemplate(null) {
@Override
public Object execute(TransactionCallback action) {
return action.doInTransaction(null);
}
@Override
public Object executeWithExceptionHandling(com.thoughtworks.go.server.transaction.TransactionCallback action) throws Exception {
// To change body of overridden methods use File | Settings | File Templates.
return super.executeWithExceptionHandling(action);
}
@Override
public <T extends Exception> Object transactionSurrounding(TransactionSurrounding<T> surrounding) throws T {
// To change body of overridden methods use File | Settings | File Templates.
return super.transactionSurrounding(surrounding);
}
};
materialUpdater = new PluggableSCMMaterialUpdater(materialRepository, scmMaterialUpdater, transactionTemplate);
}
use of org.springframework.transaction.support.TransactionCallback in project gocd by gocd.
the class JobRerunScheduleServiceTest method shouldSynchronizeAroundRerunJobsFlow.
@Test
void shouldSynchronizeAroundRerunJobsFlow() throws InterruptedException {
PipelineConfig mingleConfig = PipelineConfigMother.createPipelineConfig("mingle", "build", "unit", "functional");
Pipeline pipeline = PipelineMother.passedPipelineInstance("mingle", "build", "unit");
final Stage firstStage = pipeline.getFirstStage();
stub(mingleConfig, pipeline, firstStage);
stubConfigMd5Cal("latest-md5");
final Semaphore sem = new Semaphore(1);
sem.acquire();
final ThreadLocal<Integer> requestNumber = new ThreadLocal<>();
final boolean[] firstRequestFinished = new boolean[] { false };
final boolean[] secondReqGotInAfterFirstFinished = new boolean[] { false };
schedulingChecker = new SchedulingCheckerService(null, null, null, null, null, null, null, null, null) {
@Override
public boolean canSchedule(OperationResult result) {
if (requestNumber.get() == 0) {
// is first request, and has lock
// now we are in the locked section, so let the other request try
sem.release();
}
if (requestNumber.get() == 1) {
// this is the second req
// was the first thread done with last bit of useful work before second came in?
secondReqGotInAfterFirstFinished[0] = firstRequestFinished[0];
}
return true;
}
@Override
public boolean canRerunStage(PipelineIdentifier pipelineIdentifier, String stageName, String username, OperationResult result) {
return true;
}
};
TestTransactionTemplate template = new TestTransactionTemplate(new TestTransactionSynchronizationManager()) {
@Override
public Object execute(TransactionCallback action) {
if (requestNumber.get() == 0) {
try {
// let the other thread try for 5 seconds
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException();
}
}
return super.execute(action);
}
};
service = new ScheduleService(goConfigService, pipelineService, stageService, schedulingChecker, mock(PipelineDao.class), mock(StageDao.class), mock(StageOrderService.class), securityService, pipelineScheduleQueue, jobInstanceService, mock(JobInstanceDao.class), mock(AgentAssignment.class), environmentConfigService, lockService, serverHealthService, template, mock(AgentService.class), null, timeProvider, null, null, mock(InstanceFactory.class), schedulingPerformanceLogger, elasticProfileService, clusterProfileService) {
@Override
public Stage scheduleStage(Pipeline pipeline, String stageName, String username, StageInstanceCreator creator, ErrorConditionHandler errorHandler) {
Stage stage = super.scheduleStage(pipeline, stageName, username, creator, errorHandler);
if (requestNumber.get() == 0) {
firstRequestFinished[0] = true;
}
return stage;
}
};
Thread firstReq = new Thread(new Runnable() {
@Override
public void run() {
requestNumber.set(0);
service.rerunJobs(firstStage, a("unit"), new HttpOperationResult());
}
});
Thread secondReq = new Thread(new Runnable() {
@Override
public void run() {
try {
requestNumber.set(1);
sem.acquire();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
service.rerunJobs(firstStage, a("unit"), new HttpOperationResult());
}
});
firstReq.start();
secondReq.start();
firstReq.join();
secondReq.join();
assertThat(secondReqGotInAfterFirstFinished[0]).as("second request should have gone-in only after first is out").isTrue();
}
Aggregations