/*************************************************************************
* (c) Copyright 2016 Hewlett Packard Enterprise Development Company LP
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
************************************************************************/
package com.eucalyptus.simplequeue.workflow;
import com.amazonaws.services.simpleworkflow.flow.ActivityTaskTimedOutException;
import com.amazonaws.services.simpleworkflow.flow.DecisionContextProvider;
import com.amazonaws.services.simpleworkflow.flow.DecisionContextProviderImpl;
import com.amazonaws.services.simpleworkflow.flow.WorkflowClock;
import com.amazonaws.services.simpleworkflow.flow.annotations.Asynchronous;
import com.amazonaws.services.simpleworkflow.flow.core.AndPromise;
import com.amazonaws.services.simpleworkflow.flow.core.Promise;
import com.amazonaws.services.simpleworkflow.flow.core.Promises;
import com.amazonaws.services.simpleworkflow.flow.core.Settable;
import com.amazonaws.services.simpleworkflow.flow.core.TryCatchFinally;
import com.eucalyptus.component.annotation.ComponentPart;
import com.eucalyptus.simplequeue.SimpleQueue;
import com.eucalyptus.simplequeue.workflow.CloudWatchActivitiesClient;
import com.eucalyptus.simplequeue.workflow.CloudWatchActivitiesClientImpl;
import com.eucalyptus.simplequeue.workflow.CloudWatchWorkflowSelfClient;
import com.eucalyptus.simplequeue.workflow.CloudWatchWorkflowSelfClientImpl;
import com.google.common.collect.Lists;
import org.apache.log4j.Logger;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CancellationException;
/**
* Created by ethomas on 10/26/16.
*/
@ComponentPart(SimpleQueue.class)
public class CloudWatchWorkflowImpl implements CloudWatchWorkflow {
private static final Logger LOG = Logger.getLogger(CloudWatchWorkflowImpl.class);
private DecisionContextProvider contextProvider
= new DecisionContextProviderImpl();
private CloudWatchWorkflowSelfClient workflowSelfClient
= new CloudWatchWorkflowSelfClientImpl();
private WorkflowClock clock
= contextProvider.getDecisionContext().getWorkflowClock();
final CloudWatchActivitiesClient activitiesClient =
new CloudWatchActivitiesClientImpl();
TryCatchFinally task = null;
private int MAX_PUT_PER_WORKFLOW = 10;
private final int PUT_PERIOD_SEC = 300;
@Override
public void sendMetrics() {
final Settable<Boolean> exception = new Settable<Boolean>();
task = new TryCatchFinally() {
@Override
protected void doTry() throws Throwable {
performPeriodicAction(0);
}
@Override
protected void doCatch(Throwable ex) throws Throwable {
if (ex instanceof ActivityTaskTimedOutException) {
LOG.warn("Put metric activity timed out");
} else if (ex instanceof CancellationException) {
;
} else {
LOG.warn("Put metric workflow failed", ex);
}
exception.set(true);
throw ex;
}
@Override
protected void doFinally() throws Throwable {
if (exception.isReady() && exception.get())
return;
else if (task.isCancelRequested())
return;
else {
workflowSelfClient.sendMetrics();
}
}
};
}
@Asynchronous
private void performPeriodicAction(final int count, Promise<?>... waitFor) {
if (count >= MAX_PUT_PER_WORKFLOW) {
return;
}
final Promise<Collection<String>> partitions = activitiesClient.getPartitions();
doSendMetrics(count, partitions);
}
@Asynchronous
private void doSendMetrics(final int count, Promise<Collection<String>> partitionsPromise) {
final List<Promise<Void>> activities = Lists.newArrayList();
final Collection<String> partitions = partitionsPromise.get();
for (final String partition : partitions) {
activities.add(activitiesClient.performWork(Promise.asPromise(partition)));
}
final Promise<Void> timer = startDaemonTimer(PUT_PERIOD_SEC);
performPeriodicAction(count + 1,
new AndPromise(timer, Promises.listOfPromisesToPromise(activities)));
}
@Asynchronous(daemon = true)
private Promise<Void> startDaemonTimer(int seconds) {
Promise<Void> timer = clock.createTimer(seconds);
return timer;
}
}