use of co.cask.cdap.api.annotation.TransactionControl in project cdap by caskdata.
the class BodyConsumerAdapter method onError.
/**
* Calls the {@link HttpContentConsumer#onError(HttpServiceResponder, Throwable)} method from a transaction.
*/
private void onError(final Throwable cause, final DelayedHttpServiceResponder responder) {
if (completed) {
return;
}
// To the HttpContentConsumer, once onError is called, no other methods will be triggered
completed = true;
TransactionControl txCtrl = Transactions.getTransactionControl(TransactionControl.IMPLICIT, HttpContentConsumer.class, delegate, "onError", HttpServiceResponder.class, Throwable.class);
try {
if (TransactionControl.IMPLICIT == txCtrl) {
transactional.execute(new TxRunnable() {
@Override
public void run(DatasetContext context) throws Exception {
delegate.onError(responder, cause);
}
});
} else {
delegate.onError(responder, cause);
}
} catch (Throwable t) {
responder.setTransactionFailureResponse(t);
LOG.warn("Exception in calling HttpContentConsumer.onError", t);
} finally {
try {
responder.execute(false);
} finally {
if (!responder.hasContentProducer()) {
contextReleaser.cancel();
}
}
}
}
use of co.cask.cdap.api.annotation.TransactionControl in project cdap by caskdata.
the class CustomActionExecutor method executeCustomAction.
private void executeCustomAction() throws Exception {
try {
customActionContext.setState(new ProgramState(ProgramStatus.INITIALIZING, null));
// AbstractCustomAction implements final initialize(context) and requires subclass to
// implement initialize(), whereas programs that directly implement CustomAction can
// override initialize(context)
TransactionControl txControl = customAction instanceof AbstractCustomAction ? Transactions.getTransactionControl(TransactionControl.IMPLICIT, AbstractCustomAction.class, customAction, "initialize") : Transactions.getTransactionControl(TransactionControl.IMPLICIT, CustomAction.class, customAction, "initialize", CustomActionContext.class);
customActionContext.initializeProgram(customAction, customActionContext, txControl, false);
customActionContext.setState(new ProgramState(ProgramStatus.RUNNING, null));
customActionContext.executeChecked(new AbstractContext.ThrowingRunnable() {
@Override
public void run() throws Exception {
customAction.run();
}
});
customActionContext.setState(new ProgramState(ProgramStatus.COMPLETED, null));
} catch (Throwable t) {
customActionContext.setState(new ProgramState(ProgramStatus.FAILED, Throwables.getRootCause(t).getMessage()));
Throwables.propagateIfPossible(t, Exception.class);
throw Throwables.propagate(t);
} finally {
TransactionControl txControl = Transactions.getTransactionControl(TransactionControl.IMPLICIT, CustomAction.class, customAction, "destroy");
customActionContext.destroyProgram(customAction, customActionContext, txControl, false);
}
}
use of co.cask.cdap.api.annotation.TransactionControl in project cdap by caskdata.
the class MapReduceRuntimeService method destroy.
/**
* Calls the destroy method of {@link ProgramLifecycle}.
*/
private void destroy(final boolean succeeded, final String failureInfo) throws Exception {
// if any exception happens during output committing, we want the MapReduce to fail.
// for that to happen it is not sufficient to set the status to failed, we have to throw an exception,
// otherwise the shutdown completes successfully and the completed() callback is called.
// thus: remember the exception and throw it at the end.
final AtomicReference<Exception> failureCause = new AtomicReference<>();
// TODO (CDAP-1952): this should be done in the output committer, to make the M/R fail if addPartition fails
try {
context.execute(new TxRunnable() {
@Override
public void run(DatasetContext ctxt) throws Exception {
ClassLoader oldClassLoader = ClassLoaders.setContextClassLoader(job.getConfiguration().getClassLoader());
try {
for (Map.Entry<String, ProvidedOutput> output : context.getOutputs().entrySet()) {
commitOutput(succeeded, output.getKey(), output.getValue().getOutputFormatProvider(), failureCause);
if (succeeded && failureCause.get() != null) {
// mapreduce was successful but this output committer failed: call onFailure() for all committers
for (ProvidedOutput toFail : context.getOutputs().values()) {
commitOutput(false, toFail.getAlias(), toFail.getOutputFormatProvider(), failureCause);
}
break;
}
}
// if there was a failure, we must throw an exception to fail the transaction
// this will roll back all the outputs and also make sure that postCommit() is not called
// throwing the failure cause: it will be wrapped in a TxFailure and handled in the outer catch()
Exception cause = failureCause.get();
if (cause != null) {
failureCause.set(null);
throw cause;
}
} finally {
ClassLoaders.setContextClassLoader(oldClassLoader);
}
}
});
} catch (TransactionFailureException e) {
LOG.error("Transaction failure when committing dataset outputs", e);
if (failureCause.get() != null) {
failureCause.get().addSuppressed(e);
} else {
failureCause.set(e);
}
}
final boolean success = succeeded && failureCause.get() == null;
context.setState(getProgramState(success, failureInfo));
final TransactionControl txControl = mapReduce instanceof ProgramLifecycle ? Transactions.getTransactionControl(TransactionControl.IMPLICIT, MapReduce.class, mapReduce, "destroy") : TransactionControl.IMPLICIT;
try {
if (TransactionControl.IMPLICIT == txControl) {
context.execute(new TxRunnable() {
@Override
public void run(DatasetContext context) throws Exception {
doDestroy(success);
}
});
} else {
doDestroy(success);
}
} catch (Throwable e) {
if (e instanceof TransactionFailureException && e.getCause() != null && !(e instanceof TransactionConflictException)) {
e = e.getCause();
}
LOG.warn("Error executing the destroy method of the MapReduce program {}", context.getProgram().getName(), e);
}
// this is needed to make the run fail if there was an exception. See comment at beginning of this method
if (failureCause.get() != null) {
throw failureCause.get();
}
}
use of co.cask.cdap.api.annotation.TransactionControl in project cdap by caskdata.
the class SparkRuntimeService method initialize.
/**
* Calls the {@link Spark#beforeSubmit(SparkClientContext)} for the pre 3.5 Spark programs, calls
* the {@link ProgramLifecycle#initialize} otherwise.
*/
@SuppressWarnings("unchecked")
private void initialize() throws Exception {
context.setState(new ProgramState(ProgramStatus.INITIALIZING, null));
// AbstractSpark implements final initialize(context) and requires subclass to
// implement initialize(), whereas programs that directly implement Spark have
// the option to override initialize(context) (if they implement ProgramLifeCycle)
final TransactionControl txControl = spark instanceof AbstractSpark ? Transactions.getTransactionControl(TransactionControl.IMPLICIT, AbstractSpark.class, spark, "initialize") : spark instanceof ProgramLifecycle ? Transactions.getTransactionControl(TransactionControl.IMPLICIT, Spark.class, spark, "initialize", SparkClientContext.class) : TransactionControl.IMPLICIT;
runtimeContext.initializeProgram(programLifecycle, txControl, false);
;
}
use of co.cask.cdap.api.annotation.TransactionControl in project cdap by caskdata.
the class FlowletRuntimeService method initFlowlet.
private void initFlowlet() throws Exception {
LOG.debug("Initializing flowlet: {}", flowletContext);
TransactionControl txControl = Transactions.getTransactionControl(TransactionControl.IMPLICIT, Flowlet.class, flowlet, "initialize", FlowletContext.class);
flowletContext.initializeProgram(flowlet, txControl, false);
LOG.debug("Flowlet initialized: {}", flowletContext);
}
Aggregations