org.openmetadata.service.events.EventPubSub Maven / Gradle / Ivy
/*
* Copyright 2021 Collate
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openmetadata.service.events;
import com.lmax.disruptor.BatchEventProcessor;
import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.util.DaemonThreadFactory;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.type.ChangeEvent;
import org.openmetadata.service.events.EventPubSub.ChangeEventHolder;
/** Change event PubSub built based on LMAX Disruptor. */
@Slf4j
public class EventPubSub {
private static Disruptor disruptor;
private static ExecutorService executor;
private static RingBuffer ringBuffer;
private static boolean started = false;
public static void start() {
if (!started) {
disruptor = new Disruptor<>(ChangeEventHolder::new, 1024, DaemonThreadFactory.INSTANCE);
// disruptor.setDefaultExceptionHandler(new DefaultExceptionHandler());
executor = Executors.newCachedThreadPool(DaemonThreadFactory.INSTANCE);
ringBuffer = disruptor.start();
LOG.info("Disruptor started");
started = true;
}
}
public static void shutdown() throws InterruptedException {
if (started) {
disruptor.shutdown();
disruptor.halt();
executor.shutdownNow();
executor.awaitTermination(10, TimeUnit.SECONDS);
disruptor = null;
ringBuffer = null;
started = false;
LOG.info("Disruptor stopped");
}
}
public static class ChangeEventHolder {
@Getter @Setter private ChangeEvent event;
}
public static class ChangeEventFactory implements EventFactory {
public ChangeEventHolder newInstance() {
return new ChangeEventHolder();
}
}
public static void publish(ChangeEvent event) {
if (event != null) {
RingBuffer ringBuffer = disruptor.getRingBuffer();
long sequence = ringBuffer.next();
ringBuffer.get(sequence).setEvent(event);
ringBuffer.publish(sequence);
}
}
public static BatchEventProcessor addEventHandler(
EventHandler eventHandler) {
BatchEventProcessor processor =
new BatchEventProcessor<>(ringBuffer, ringBuffer.newBarrier(), eventHandler);
// processor.setExceptionHandler(new DefaultExceptionHandler());
ringBuffer.addGatingSequences(processor.getSequence());
executor.execute(processor);
LOG.info("Processor added for {}", processor);
return processor;
}
public static void removeProcessor(BatchEventProcessor processor) {
ringBuffer.removeGatingSequence(processor.getSequence());
LOG.info("Processor removed for {}", processor);
}
public void close() {
/* Nothing to clean up */
}
}