All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ru.qatools.mongodb.MongoTailableQueue Maven / Gradle / Ivy

package ru.qatools.mongodb;

import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.CreateCollectionOptions;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.function.Consumer;

import static com.mongodb.CursorType.TailableAwait;
import static java.lang.Thread.sleep;
import static java.util.stream.StreamSupport.stream;

/**
 * @author Ilya Sadykov
 */
public class MongoTailableQueue extends MongoAbstractStorage
        implements TailableQueue {
    public static final long DEFAULT_MAX_SIZE = 1000L;
    public static final long ASSUMED_MAX_DOC_SIZE = 1024L * 1024L; // 1mb
    public static final int BATCH_SIZE = 100;
    public static final int SLEEP_BETWEEN_FAILURES_MS = 500;
    public static final int MIN_POLL_INTERVAL_MS = 100;
    private static final Logger LOGGER = LoggerFactory.getLogger(MongoTailableQueue.class);
    final MongoClient mongo;
    final String dbName;
    final String queueName;
    final long maxSize;
    volatile boolean stopped = false;
    private int minPollIntervalMs = MIN_POLL_INTERVAL_MS;
    private int sleepBetweenFailuresMs = SLEEP_BETWEEN_FAILURES_MS;

    public MongoTailableQueue(Class entityClass, MongoClient mongo, String dbName, String queueName) {
        this(entityClass, mongo, dbName, queueName, DEFAULT_MAX_SIZE);
    }

    public MongoTailableQueue(Class entityClass, MongoClient mongo, String dbName, String queueName, long maxSize) {
        super(entityClass);
        this.mongo = mongo;
        this.dbName = dbName;
        this.queueName = queueName;
        this.maxSize = maxSize;
    }

    @Override
    public void drop() {
        collection().drop();
    }

    @Override
    public void init() {
        if (stream(db().listCollectionNames().spliterator(), false)
                .filter(s -> s.equals(queueName)).count() == 0) {
            db().createCollection(queueName,
                    new CreateCollectionOptions().capped(true)
                            .maxDocuments(maxSize)
                            .sizeInBytes(ASSUMED_MAX_DOC_SIZE * maxSize)
                            .autoIndex(true));
        }
    }

    @Override
    public void stop() {
        this.stopped = true;
    }

    @Override
    public void poll(Consumer consumer) {
        if (stopped) {
            LOGGER.warn("Could not stopped queue {}.{}", dbName, queueName);
        }
        while (!stopped) {
            try {
                stream(collection().find()
                        .cursorType(TailableAwait)
                        .noCursorTimeout(true)
                        .batchSize(BATCH_SIZE).spliterator(), false)
                        .forEach(doc -> consumer.accept(getObject(doc, entityClass)));
                try {
                    LOGGER.debug("Tailable cursor returned no value without await for {}.{}", dbName, queueName);
                    sleep(minPollIntervalMs);
                } catch (InterruptedException e) {
                    LOGGER.warn("Poll sleeping after cursor returns was interrupted", e);
                }
            } catch (MongoException e) {
                LOGGER.debug("Failed to iterate on queue cursor for {}.{}", dbName, queueName, e);
                try {
                    sleep(sleepBetweenFailuresMs);
                } catch (InterruptedException e1) {
                    LOGGER.warn("Poll sleeping after cursor failure was interrupted", e);
                }
            }
        }
    }

    @Override
    public void add(T object) {
        collection().insertOne(Document.parse(serializer.toDBObject(object).toJson()));
    }

    @Override
    public long size() {
        return collection().count();
    }

    public void setMinPollIntervalMs(int minPollIntervalMs) {
        this.minPollIntervalMs = minPollIntervalMs;
    }

    public void setSleepBetweenFailuresMs(int sleepBetweenFailuresMs) {
        this.sleepBetweenFailuresMs = sleepBetweenFailuresMs;
    }

    private MongoCollection collection() {
        return db().getCollection(queueName);
    }

    private MongoDatabase db() {
        return mongo.getDatabase(dbName);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy