我已经编写了名为mysink的定制flume sink,其处理方法在下面的第一个片段中指明。我得到一个illegalstateexception,如下所示(下面的第2个代码段提供了详细的堆栈跟踪):
原因:java.lang.illegalstateexception:事务打开时调用的begin()!
问:在编写process方法时,我在flume代码库中遵循了kafkasink和类似的现有sink实现,并且我正在对那些现有sink应用相同的事务处理逻辑。你能告诉我这里的处理方法有什么问题吗?我怎样才能解决这个问题?
进程方法(我已标记引发异常的位置):
@Override
public Status process() throws EventDeliveryException {
Status status = Status.READY;
Channel ch = getChannel();
Transaction txn = ch.getTransaction();
Event event = null;
try {
LOG.info(getName() + " BEFORE txn.begin()");
//!!!! EXCEPTION IS THROWN in the following LINE !!!!!!
txn.begin();
LOG.info(getName() + " AFTER txn.begin()");
LOG.info(getName() + " BEFORE ch.take()");
event = ch.take();
LOG.info(getName() + " AFTER ch.take()");
if (event == null) {
// No event found, request back-off semantics from the sink runner
LOG.info(getName() + " - EVENT is null! ");
return Status.BACKOFF;
}
Map<String, String> keyValueMapInTheMessage = event.getHeaders();
if (!keyValueMapInTheMessage.isEmpty()) {
mDBWriter.insertDataToDB(keyValueMapInTheMessage);
}
LOG.info(getName() + " - EVENT: " + EventHelper.dumpEvent(event));
if (txn != null) {
txn.commit();
}
} catch (Exception ex) {
String errMsg = getName() + " - Failed to publish events. Exception: ";
LOG.info(errMsg);
status = Status.BACKOFF;
if (txn != null) {
try {
txn.rollback();
} catch (Exception e) {
LOG.info(getName() + " - EVENT: " + EventHelper.dumpEvent(event));
throw Throwables.propagate(e);
}
}
throw new EventDeliveryException(errMsg, ex);
} finally {
if (txn != null) {
txn.close();
}
}
return status;
}
异常堆栈:
2016-01-22 14:01:15,440 (SinkRunner-PollingRunner-DefaultSinkProcessor) [ERROR - org.apache.flume.SinkRunner$PollingRunner.run(SinkRunner.java:160)]
Unable to deliver event. Exception follows.
org.apache.flume.EventDeliveryException: MySink - Failed to publish events.
Exception: at com.XYZ.flume.maprdb.MySink.process(MySink.java:116)
at org.apache.flume.sink.DefaultSinkProcessor.process(DefaultSinkProcessor.java:68)
at org.apache.flume.SinkRunner$PollingRunner.run(SinkRunner.java:147)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: begin() called when transaction is OPEN!
at com.google.common.base.Preconditions.checkState(Preconditions.java:145)
at org.apache.flume.channel.BasicTransactionSemantics.begin(BasicTransactionSemantics.java:131)
at com.XYZ.flume.maprdb.MySink.process(MySink.java:82)
... 3 more
1条答案
按热度按时间bis0qfac1#
此代码导致此问题。当event为null时,您只需返回它。但是,正确的方法是提交或回滚。事务应该经历三个阶段:begin、commit或rollback、finally close。
基本通道语义:
当currenttransaction为null或其状态为close时,通道将创建一个新的,否则返回旧的。这种例外情况不会立即发生。第一次执行process方法时,得到一个新的事务,但是事件为null,只返回并最终关闭,close方法因为它的实现而不起作用。所以第二次执行process方法时,没有得到一个新的事务,它是旧的事务。下面的代码是关于事务如何实现的。
基本交易语义:
创建时,状态是新的。
开始时,状态必须是新的,然后状态变为开放的。
提交或回滚时,状态必须是open,然后状态变为complete。
关闭时,状态必须完整,然后状态变为关闭。
所以当你以正确的方式执行close方法时,下次你会得到一个新的事务,否则状态为new的旧事务就不能执行transaction.begin(),它需要一个新的事务。