mirror of https://github.com/apache/nifi.git
NIFI-11092 Fixed ConsumeTwitter handling on Primary Node changes
This closes #6901 Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
parent
28bfd1252f
commit
0b61a6226c
|
@ -26,6 +26,8 @@ import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||||
import org.apache.nifi.annotation.documentation.Tags;
|
import org.apache.nifi.annotation.documentation.Tags;
|
||||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||||
import org.apache.nifi.annotation.lifecycle.OnStopped;
|
import org.apache.nifi.annotation.lifecycle.OnStopped;
|
||||||
|
import org.apache.nifi.annotation.notification.OnPrimaryNodeStateChange;
|
||||||
|
import org.apache.nifi.annotation.notification.PrimaryNodeState;
|
||||||
import org.apache.nifi.components.AllowableValue;
|
import org.apache.nifi.components.AllowableValue;
|
||||||
import org.apache.nifi.components.PropertyDescriptor;
|
import org.apache.nifi.components.PropertyDescriptor;
|
||||||
import org.apache.nifi.flowfile.FlowFile;
|
import org.apache.nifi.flowfile.FlowFile;
|
||||||
|
@ -49,6 +51,7 @@ import java.util.HashMap;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
@PrimaryNodeOnly
|
@PrimaryNodeOnly
|
||||||
|
@ -255,6 +258,8 @@ public class ConsumeTwitter extends AbstractProcessor {
|
||||||
|
|
||||||
private volatile BlockingQueue<String> messageQueue;
|
private volatile BlockingQueue<String> messageQueue;
|
||||||
|
|
||||||
|
private final AtomicBoolean streamStarted = new AtomicBoolean(false);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init(ProcessorInitializationContext context) {
|
protected void init(ProcessorInitializationContext context) {
|
||||||
final List<PropertyDescriptor> descriptors = new ArrayList<>();
|
final List<PropertyDescriptor> descriptors = new ArrayList<>();
|
||||||
|
@ -296,13 +301,13 @@ public class ConsumeTwitter extends AbstractProcessor {
|
||||||
@OnScheduled
|
@OnScheduled
|
||||||
public void onScheduled(final ProcessContext context) {
|
public void onScheduled(final ProcessContext context) {
|
||||||
messageQueue = new LinkedBlockingQueue<>(context.getProperty(QUEUE_SIZE).asInteger());
|
messageQueue = new LinkedBlockingQueue<>(context.getProperty(QUEUE_SIZE).asInteger());
|
||||||
|
streamStarted.set(false);
|
||||||
tweetStreamService = new TweetStreamService(context, messageQueue, getLogger());
|
|
||||||
tweetStreamService.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrigger(ProcessContext context, ProcessSession session) throws ProcessException {
|
public void onTrigger(ProcessContext context, ProcessSession session) throws ProcessException {
|
||||||
|
startTweetStreamService(context);
|
||||||
|
|
||||||
final String firstTweet = messageQueue.poll();
|
final String firstTweet = messageQueue.poll();
|
||||||
if (firstTweet == null) {
|
if (firstTweet == null) {
|
||||||
context.yield();
|
context.yield();
|
||||||
|
@ -338,15 +343,41 @@ public class ConsumeTwitter extends AbstractProcessor {
|
||||||
session.getProvenanceReporter().receive(flowFile, transitUri);
|
session.getProvenanceReporter().receive(flowFile, transitUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OnPrimaryNodeStateChange
|
||||||
|
public void onPrimaryNodeStateChange(final PrimaryNodeState newState) {
|
||||||
|
if (newState == PrimaryNodeState.PRIMARY_NODE_REVOKED) {
|
||||||
|
stopTweetStreamService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OnStopped
|
@OnStopped
|
||||||
public void onStopped() {
|
public void onStopped() {
|
||||||
if (tweetStreamService != null) {
|
stopTweetStreamService();
|
||||||
tweetStreamService.stop();
|
|
||||||
}
|
|
||||||
tweetStreamService = null;
|
|
||||||
emptyQueue();
|
emptyQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startTweetStreamService(final ProcessContext context) {
|
||||||
|
if (streamStarted.compareAndSet(false, true)) {
|
||||||
|
tweetStreamService = new TweetStreamService(context, messageQueue, getLogger());
|
||||||
|
tweetStreamService.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopTweetStreamService() {
|
||||||
|
if (streamStarted.compareAndSet(true, false)) {
|
||||||
|
if (tweetStreamService != null) {
|
||||||
|
tweetStreamService.stop();
|
||||||
|
}
|
||||||
|
tweetStreamService = null;
|
||||||
|
|
||||||
|
if (!messageQueue.isEmpty()) {
|
||||||
|
getLogger().warn("Stopped consuming stream: unprocessed messages [{}]", messageQueue.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void emptyQueue() {
|
private void emptyQueue() {
|
||||||
while (!messageQueue.isEmpty()) {
|
while (!messageQueue.isEmpty()) {
|
||||||
messageQueue.poll();
|
messageQueue.poll();
|
||||||
|
|
|
@ -44,7 +44,8 @@ public class TweetStreamService {
|
||||||
private final BlockingQueue<String> queue;
|
private final BlockingQueue<String> queue;
|
||||||
private final ComponentLog logger;
|
private final ComponentLog logger;
|
||||||
|
|
||||||
private final ScheduledExecutorService executorService;
|
private ScheduledExecutorService executorService;
|
||||||
|
private final ThreadFactory threadFactory;
|
||||||
|
|
||||||
private final Set<String> tweetFields;
|
private final Set<String> tweetFields;
|
||||||
private final Set<String> userFields;
|
private final Set<String> userFields;
|
||||||
|
@ -107,8 +108,7 @@ public class TweetStreamService {
|
||||||
final String basePath = context.getProperty(ConsumeTwitter.BASE_PATH).getValue();
|
final String basePath = context.getProperty(ConsumeTwitter.BASE_PATH).getValue();
|
||||||
api.getApiClient().setBasePath(basePath);
|
api.getApiClient().setBasePath(basePath);
|
||||||
|
|
||||||
final ThreadFactory threadFactory = new BasicThreadFactory.Builder().namingPattern(ConsumeTwitter.class.getSimpleName()).build();
|
threadFactory = new BasicThreadFactory.Builder().namingPattern(ConsumeTwitter.class.getSimpleName()).build();
|
||||||
this.executorService = Executors.newSingleThreadScheduledExecutor(threadFactory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTransitUri(final String endpoint) {
|
public String getTransitUri(final String endpoint) {
|
||||||
|
@ -128,6 +128,7 @@ public class TweetStreamService {
|
||||||
* to run until {@code stop} is called.
|
* to run until {@code stop} is called.
|
||||||
*/
|
*/
|
||||||
public void start() {
|
public void start() {
|
||||||
|
this.executorService = Executors.newSingleThreadScheduledExecutor(threadFactory);
|
||||||
executorService.execute(new TweetStreamStarter());
|
executorService.execute(new TweetStreamStarter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +146,7 @@ public class TweetStreamService {
|
||||||
}
|
}
|
||||||
|
|
||||||
executorService.shutdownNow();
|
executorService.shutdownNow();
|
||||||
|
executorService = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Long calculateBackoffDelay() {
|
private Long calculateBackoffDelay() {
|
||||||
|
|
Loading…
Reference in New Issue