/* * Copyright (c) 2010-2012 Grid Dynamics Consulting Services, Inc, All Rights Reserved * http://www.griddynamics.com * * This library is free software; you can redistribute it and/or modify it under the terms of * the Apache License; either * version 2.0 of the License, or any later version. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.griddynamics.jagger.engine.e1.scenario; import static com.griddynamics.jagger.util.TimeUtils.sleepMillis; import com.griddynamics.jagger.coordinator.Coordinator; import com.griddynamics.jagger.coordinator.NodeContext; import com.griddynamics.jagger.coordinator.NodeId; import com.griddynamics.jagger.coordinator.NodeType; import com.griddynamics.jagger.coordinator.Qualifier; import com.griddynamics.jagger.coordinator.RemoteExecutor; import com.griddynamics.jagger.dbapi.entity.TaskData; import com.griddynamics.jagger.engine.e1.ProviderUtil; import com.griddynamics.jagger.engine.e1.collector.test.TestInfo; import com.griddynamics.jagger.engine.e1.collector.test.TestListener; import com.griddynamics.jagger.engine.e1.process.PollWorkloadProcessStatus; import com.griddynamics.jagger.engine.e1.process.StartWorkloadProcess; import com.griddynamics.jagger.engine.e1.process.StopWorkloadProcess; import com.griddynamics.jagger.engine.e1.services.JaggerPlace; import com.griddynamics.jagger.master.AbstractDistributionService; import com.griddynamics.jagger.master.AbstractDistributor; import com.griddynamics.jagger.master.TaskExecutionStatusProvider; import com.griddynamics.jagger.util.TimeUtils; import com.griddynamics.jagger.util.TimeoutsConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Required; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.google.common.util.concurrent.Service; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; public class WorkloadTaskDistributor extends AbstractDistributor<WorkloadTask> { private static Logger log = LoggerFactory.getLogger(WorkloadTaskDistributor.class); private TimeoutsConfiguration timeoutsConfiguration; private TaskExecutionStatusProvider taskExecutionStatusProvider; private long logInterval; private String classesUrl; public void setClassesUrl(String classesUrl) { this.classesUrl = classesUrl; } @Override public Set<Qualifier<?>> getQualifiers() { Set<Qualifier<?>> result = Sets.newHashSet(); result.add(Qualifier.of(StartWorkloadProcess.class)); result.add(Qualifier.of(StopWorkloadProcess.class)); result.add(Qualifier.of(PollWorkloadProcessStatus.class)); return result; } public void setTaskExecutionStatusProvider(TaskExecutionStatusProvider taskExecutionStatusProvider) { this.taskExecutionStatusProvider = taskExecutionStatusProvider; } @Required public void setTimeoutsConfiguration(TimeoutsConfiguration timeoutsConfiguration) { this.timeoutsConfiguration = timeoutsConfiguration; } @Override protected Service performDistribution(final ExecutorService executor, final String sessionId, final String taskId, final WorkloadTask task, final Map<NodeId, RemoteExecutor> remotes, final Multimap<NodeType, NodeId> availableNodes, final Coordinator coordinator, final NodeContext nodeContext) { return new AbstractDistributionService(executor) { @Override protected void run() throws Exception { //create test-listener TestListener testListener = TestListener.Composer.compose(ProviderUtil.provideElements(task.getTestListeners(), sessionId, taskId, nodeContext, JaggerPlace.TEST_LISTENER)); // start time must be initialized after calibration // if start time will not initialize(calibration) - set 0 test duration Long startTime = null; //create status info TestInfo testInfo = new TestInfo(task, sessionId); DefaultWorkloadController controller = null; try { taskExecutionStatusProvider.setStatus(taskId, TaskData.ExecutionStatus.IN_PROGRESS); testListener.onStart(testInfo); String line = " ---------------------------------------------------------------------------------------------------------------------------------------------------\n"; String report = "\n\n" + line + "S T A R T W O R K L O A D\n" + line + "\n"; log.info(report); log.info("Going to distribute workload task {}", task); if (task.getStartDelay() > 0) { log.info("Going to sleep '{}' ms before execute task: {}", task.getStartDelay(), task.getName()); TimeUtils.sleepMillis(task.getStartDelay()); log.info("Start execution of task: {}", task); } startTime = System.currentTimeMillis() ; controller = new DefaultWorkloadController(sessionId, taskId, task, remotes, timeoutsConfiguration, startTime); controller.setClassesUrl(classesUrl); WorkloadClock clock = task.getClock(); TerminationStrategy terminationStrategy = task.getTerminationStrategy(); log.debug("Going to start workload"); controller.startWorkload(clock.getPoolSizes(controller.getNodes())); log.debug("Workload started"); int sleepInterval = clock.getTickInterval(); long multiplicity = logInterval / sleepInterval; long countIntervals = 0; while (true) { if (!isRunning()) { log.info("Going to terminate work {}. Requested from outside",task.getName()); break; } WorkloadExecutionStatus status = controller.getStatus(); // update status for test-listeners testInfo.setSamples(status.getTotalSamples()); testInfo.setStartedSamples(status.getTotalStartedSamples()); testInfo.setThreads(status.getTotalThreads()); testInfo.setDuration(System.currentTimeMillis() - startTime); testListener.onRun(testInfo); if (terminationStrategy.isTerminationRequired(status)) { report = "\n\n" + line + "S T O P W O R K L O A D\n" + line + "\n"; log.info(report); log.info("Going to terminate work {}. According to termination strategy",task.getName()); break; } clock.tick(status, controller); if (--countIntervals <= 0) { log.info("Status of execution {}", status); countIntervals = multiplicity; } log.debug("Clock should continue. Going to sleep {} seconds", sleepInterval); sleepMillis(sleepInterval); } taskExecutionStatusProvider.setStatus(taskId, TaskData.ExecutionStatus.SUCCEEDED); } catch (Exception e) { taskExecutionStatusProvider.setStatus(taskId, TaskData.ExecutionStatus.FAILED); log.error("Workload task error: ", e); } finally { if(controller != null) { log.debug("Going to stop workload"); controller.stopWorkload(); log.debug("Workload stopped"); } testInfo.setThreads(0); if (startTime == null){ testInfo.setDuration(0L); }else{ testInfo.setDuration(System.currentTimeMillis()-startTime); } testListener.onStop(testInfo); } } @Override public String toString() { return WorkloadTask.class.getName() + " distributor"; } }; } public void setLogInterval(long logInterval) { this.logInterval = logInterval; } }