use of org.apache.pulsar.functions.instance.state.StateContextImpl in project incubator-pulsar by apache.
the class JavaInstanceRunnable method run.
/**
* The core logic that initialize the instance thread and executes the function
*/
@Override
public void run() {
try {
javaInstance = setupJavaInstance();
while (running) {
// some src topics might be put into resubscribe list because of processing failure
// so this is the chance to resubscribe to those topics.
resubscribeTopicsIfNeeded();
JavaExecutionResult result;
InputMessage msg;
try {
msg = queue.take();
log.debug("Received message: {}", msg.getActualMessage().getMessageId());
} catch (InterruptedException ie) {
log.info("Function thread {} is interrupted", FunctionConfigUtils.getFullyQualifiedName(instanceConfig.getFunctionConfig()), ie);
break;
}
if (ProcessingGuarantees.EFFECTIVELY_ONCE == processingGuarantees) {
// re-created for the correctness of effectively-once
if (msg.getConsumer() != inputConsumers.get(msg.getTopicName())) {
continue;
}
}
if (null != outputProducer) {
// before processing the message, we have a producer connection setup for producing results.
Producer producer = null;
while (null == producer) {
try {
producer = outputProducer.getProducer(msg.getTopicName(), msg.getTopicPartition());
} catch (PulsarClientException e) {
// so we need to wait until the old active consumer release the produce connection.
if (!(e instanceof ProducerBusyException)) {
log.error("Failed to get a producer for producing results computed from input topic {}", msg.getTopicName());
}
TimeUnit.MILLISECONDS.sleep(500);
}
}
}
// state object is per function, because we need to have the ability to know what updates
// are made in this function and ensure we only acknowledge after the state is persisted.
StateContextImpl stateContext;
if (null != stateTable) {
stateContext = new StateContextImpl(stateTable);
javaInstance.getContext().setStateContext(stateContext);
} else {
stateContext = null;
}
// process the message
Object input;
try {
input = msg.getInputSerDe().deserialize(msg.getActualMessage().getData());
} catch (Exception ex) {
stats.incrementDeserializationExceptions(msg.getTopicName());
continue;
}
long processAt = System.currentTimeMillis();
stats.incrementProcessed(processAt);
addLogTopicHandler();
result = javaInstance.handleMessage(msg.getActualMessage().getMessageId(), msg.getTopicName(), input);
removeLogTopicHandler();
long doneProcessing = System.currentTimeMillis();
log.debug("Got result: {}", result.getResult());
if (null != stateContext) {
stateContext.flush().thenRun(() -> processResult(msg, result, processAt, doneProcessing)).exceptionally(cause -> {
// log the messages, since we DONT ack, pulsar consumer will re-deliver the messages.
log.error("Failed to flush the state updates of message {}", msg, cause);
return null;
});
} else {
processResult(msg, result, processAt, doneProcessing);
}
}
javaInstance.close();
} catch (Exception ex) {
log.info("Uncaught exception in Java Instance", ex);
failureException = ex;
}
}
Aggregations