/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ambari.server.state.scheduler;
import java.util.HashMap;
import java.util.Map;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.actionmanager.HostRoleStatus;
import org.apache.ambari.server.scheduler.AbstractLinearExecutionJob;
import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.PersistJobDataAfterExecution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.google.inject.name.Named;
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class BatchRequestJob extends AbstractLinearExecutionJob {
private static final Logger LOG = LoggerFactory.getLogger(BatchRequestJob.class);
public static final String BATCH_REQUEST_EXECUTION_ID_KEY =
"BatchRequestJob.ExecutionId";
public static final String BATCH_REQUEST_BATCH_ID_KEY =
"BatchRequestJob.BatchId";
public static final String BATCH_REQUEST_CLUSTER_NAME_KEY =
"BatchRequestJob.ClusterName";
public static final String BATCH_REQUEST_FAILED_TASKS_KEY =
"BatchRequestJob.FailedTaskCount";
public static final String BATCH_REQUEST_TOTAL_TASKS_KEY =
"BatchRequestJob.TotalTaskCount";
private final long statusCheckInterval;
@Inject
public BatchRequestJob(ExecutionScheduleManager executionScheduleManager,
@Named("statusCheckInterval") long statusCheckInterval) {
super(executionScheduleManager);
this.statusCheckInterval = statusCheckInterval;
}
@Override
protected void doWork(Map<String, Object> properties) throws AmbariException {
Long executionId = properties.get(BATCH_REQUEST_EXECUTION_ID_KEY) != null ?
(Long) properties.get(BATCH_REQUEST_EXECUTION_ID_KEY) : null;
Long batchId = properties.get(BATCH_REQUEST_BATCH_ID_KEY) != null ?
(Long) properties.get(BATCH_REQUEST_BATCH_ID_KEY) : null;
String clusterName = (String) properties.get(BATCH_REQUEST_CLUSTER_NAME_KEY);
if (executionId == null || batchId == null) {
throw new AmbariException("Unable to retrieve persisted batch request"
+ ", execution_id = " + executionId
+ ", batch_id = " + batchId);
}
// Aggregate tasks counts stored in the DataMap
Map<String, Integer> taskCounts = getTaskCountProperties(properties);
Long requestId = executionScheduleManager.executeBatchRequest
(executionId, batchId, clusterName);
if (requestId != null) {
HostRoleStatus status;
BatchRequestResponse batchRequestResponse;
do {
batchRequestResponse = executionScheduleManager
.getBatchRequestResponse(requestId, clusterName);
status = HostRoleStatus.valueOf(batchRequestResponse.getStatus());
executionScheduleManager.updateBatchRequest(executionId, batchId,
clusterName, batchRequestResponse, true);
try {
Thread.sleep(statusCheckInterval);
} catch (InterruptedException e) {
String message = "Job Thread interrupted";
LOG.error(message, e);
throw new AmbariException(message, e);
}
} while (!status.isCompletedState());
// Store aggregated task status counts in the DataMap
Map<String, Integer> aggregateCounts = addTaskCountToProperties
(properties, taskCounts, batchRequestResponse);
if (executionScheduleManager.hasToleranceThresholdExceeded
(executionId, clusterName, aggregateCounts)) {
throw new AmbariException("Task failure tolerance limit exceeded"
+ ", execution_id = " + executionId
+ ", processed batch_id = " + batchId
+ ", failed tasks = " + aggregateCounts.get(BATCH_REQUEST_FAILED_TASKS_KEY)
+ ", total tasks completed = " + aggregateCounts.get(BATCH_REQUEST_TOTAL_TASKS_KEY));
}
}
}
@Override
protected void finalizeExecution(Map<String, Object> properties)
throws AmbariException {
Long executionId = properties.get(BATCH_REQUEST_EXECUTION_ID_KEY) != null ?
(Long) properties.get(BATCH_REQUEST_EXECUTION_ID_KEY) : null;
Long batchId = properties.get(BATCH_REQUEST_BATCH_ID_KEY) != null ?
(Long) properties.get(BATCH_REQUEST_BATCH_ID_KEY) : null;
String clusterName = (String) properties.get(BATCH_REQUEST_CLUSTER_NAME_KEY);
if (executionId == null || batchId == null) {
throw new AmbariException("Unable to retrieve persisted batch request"
+ ", execution_id = " + executionId
+ ", batch_id = " + batchId);
}
// Check if this job has a future and update status if it doesn't
executionScheduleManager.finalizeBatch(executionId, clusterName);
}
private Map<String, Integer> addTaskCountToProperties(Map<String, Object> properties,
Map<String, Integer> oldCounts,
BatchRequestResponse batchRequestResponse) {
Map<String, Integer> taskCounts = new HashMap<>();
if (batchRequestResponse != null) {
Integer failedTasks = batchRequestResponse.getFailedTaskCount() +
batchRequestResponse.getAbortedTaskCount() +
batchRequestResponse.getTimedOutTaskCount();
Integer failedCount = oldCounts.get(BATCH_REQUEST_FAILED_TASKS_KEY) + failedTasks;
Integer totalCount = oldCounts.get(BATCH_REQUEST_TOTAL_TASKS_KEY) +
batchRequestResponse.getTotalTaskCount();
taskCounts.put(BATCH_REQUEST_FAILED_TASKS_KEY, failedCount);
taskCounts.put(BATCH_REQUEST_TOTAL_TASKS_KEY, totalCount);
properties.put(BATCH_REQUEST_FAILED_TASKS_KEY, failedCount);
properties.put(BATCH_REQUEST_TOTAL_TASKS_KEY, totalCount);
}
return taskCounts;
}
private Map<String, Integer> getTaskCountProperties(Map<String, Object> properties) {
Map<String, Integer> taskCounts = new HashMap<>();
if (properties != null) {
Object countObj = properties.get(BATCH_REQUEST_FAILED_TASKS_KEY);
taskCounts.put(BATCH_REQUEST_FAILED_TASKS_KEY,
countObj != null ? Integer.parseInt(countObj.toString()) : 0);
countObj = properties.get(BATCH_REQUEST_TOTAL_TASKS_KEY);
taskCounts.put(BATCH_REQUEST_TOTAL_TASKS_KEY, countObj != null ?
Integer.parseInt(countObj.toString()) : 0);
}
return taskCounts;
}
}