use of io.confluent.ksql.rest.server.resources.KsqlRestException in project ksql by confluentinc.
the class DistributingExecutor method execute.
/**
* The transactional protocol for sending a command to the command topic is to
* initTransaction(), beginTransaction(), wait for commandRunner to finish processing all previous
* commands that were present at the start of the transaction, validate the current command,
* enqueue the command in the command topic, and commit the transaction.
* Only successfully committed commands can be read by the command topic consumer.
* If any exceptions are thrown during this protocol, the transaction is aborted.
* If a new transactional producer is initialized while the current transaction is incomplete,
* the old producer will be fenced off and unable to continue with its transaction.
*/
// CHECKSTYLE_RULES.OFF: NPathComplexity
public StatementExecutorResponse execute(final ConfiguredStatement<? extends Statement> statement, final KsqlExecutionContext executionContext, final KsqlSecurityContext securityContext) {
final String commandRunnerWarningString = commandRunnerWarning.get();
if (!commandRunnerWarningString.equals("")) {
throw new KsqlServerException("Failed to handle Ksql Statement." + System.lineSeparator() + commandRunnerWarningString);
}
final ConfiguredStatement<?> injected = injectorFactory.apply(executionContext, securityContext.getServiceContext()).inject(statement);
if (injected.getStatement() instanceof InsertInto) {
validateInsertIntoQueries(executionContext.getMetaStore(), (InsertInto) injected.getStatement());
}
final Optional<StatementExecutorResponse> response = checkIfNotExistsResponse(executionContext, statement);
if (response.isPresent()) {
return response.get();
}
checkAuthorization(injected, securityContext, executionContext);
final Producer<CommandId, Command> transactionalProducer = commandQueue.createTransactionalProducer();
try {
transactionalProducer.initTransactions();
} catch (final TimeoutException e) {
throw new KsqlServerException(errorHandler.transactionInitTimeoutErrorMessage(e), e);
} catch (final Exception e) {
throw new KsqlServerException(String.format("Could not write the statement '%s' into the command topic: " + e.getMessage(), statement.getStatementText()), e);
}
if (!rateLimiter.tryAcquire(1, TimeUnit.SECONDS)) {
throw new KsqlRestException(Errors.tooManyRequests("DDL/DML rate is crossing the configured rate limit of statements/second"));
}
CommandId commandId = null;
try {
transactionalProducer.beginTransaction();
commandQueue.waitForCommandConsumer();
commandId = commandIdAssigner.getCommandId(statement.getStatement());
final Command command = validatedCommandFactory.create(injected, executionContext.createSandbox(executionContext.getServiceContext()));
final QueuedCommandStatus queuedCommandStatus = commandQueue.enqueueCommand(commandId, command, transactionalProducer);
transactionalProducer.commitTransaction();
final CommandStatus commandStatus = queuedCommandStatus.tryWaitForFinalStatus(distributedCmdResponseTimeout);
return StatementExecutorResponse.handled(Optional.of(new CommandStatusEntity(injected.getStatementText(), queuedCommandStatus.getCommandId(), commandStatus, queuedCommandStatus.getCommandSequenceNumber(), getDeprecatedWarnings(executionContext.getMetaStore(), injected))));
} catch (final ProducerFencedException | OutOfOrderSequenceException | AuthorizationException e) {
// This catch doesn't abortTransaction() since doing that would throw another exception.
if (commandId != null) {
commandQueue.abortCommand(commandId);
}
throw new KsqlServerException(String.format("Could not write the statement '%s' into the command topic.", statement.getStatementText()), e);
} catch (final Exception e) {
transactionalProducer.abortTransaction();
if (commandId != null) {
commandQueue.abortCommand(commandId);
}
throw new KsqlServerException(String.format("Could not write the statement '%s' into the command topic.", statement.getStatementText()), e);
} finally {
transactionalProducer.close();
}
}
Aggregations