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

com.playtika.shepherd.KafkaPushFarm Maven / Gradle / Ivy

There is a newer version: 0.1.8
Show newest version
package com.playtika.shepherd;

import com.playtika.shepherd.common.PastureListener;
import com.playtika.shepherd.common.push.Farm;
import com.playtika.shepherd.common.push.Pasture;
import com.playtika.shepherd.common.push.Shepherd;
import com.playtika.shepherd.inernal.Herd;
import com.playtika.shepherd.inernal.PastureShepherd;
import com.playtika.shepherd.inernal.PastureShepherdBuilder;
import com.playtika.shepherd.inernal.Population;
import com.playtika.shepherd.serde.SerDe;

import java.nio.ByteBuffer;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

import static com.playtika.shepherd.inernal.CheckedHerd.checked;
import static com.playtika.shepherd.inernal.utils.CacheUtils.memoize;
import static com.playtika.shepherd.serde.SerDeUtils.BYTE_BUFFER_DE_SER;
import static com.playtika.shepherd.serde.SerDeUtils.getSerDe;

public class KafkaPushFarm implements Farm {

    public static final int NO_VERSION = -1;
    private final String bootstrapServers;
    private final Map properties;

    public KafkaPushFarm(String bootstrapServers) {
        this(bootstrapServers, Map.of());
    }

    public KafkaPushFarm(String bootstrapServers, Map properties) {
        this.bootstrapServers = bootstrapServers;
        this.properties = properties;
    }

    @Override
    public Pasture addPasture(String herdName, PastureListener pastureListener) {
        return addBreedingPasture(herdName, BYTE_BUFFER_DE_SER, pastureListener);
    }

    @Override
    public  Pasture addBreedingPasture(String herdName, Class breedClass, PastureListener pastureListener) {
        return addBreedingPasture(herdName, getSerDe(breedClass), pastureListener);
    }

    private   Pasture addBreedingPasture(String herdName, SerDe serDe, PastureListener pastureListener){
        PushHerd pushHerd = new PushHerd<>(pastureListener, serDe);

        PastureShepherd pastureShepherd = new PastureShepherdBuilder()
                .setBootstrapServers(bootstrapServers)
                .setGroupId(herdName)
                .setProperties(properties)
                .setRebalanceListener(pushHerd)
                .setHerd(checked(pushHerd))
                .build();

        pushHerd.setPastureShepherd(pastureShepherd);

        return pushHerd;
    }

    @Override
    public String toString() {
        return "KafkaFarm{" +
                "bootstrapServers='" + bootstrapServers + '\'' +
                ", properties=" + properties +
                '}';
    }

    static final class PushHerd implements Herd, Pasture, Shepherd, PastureListener {

        private final PastureListener pastureListener;
        private final SerDe serDe;

        private PastureShepherd pastureShepherd;

        private Population snapshot;
        private Population latest;

        private long assignedVersion = Long.MIN_VALUE;

        PushHerd(PastureListener pastureListener, SerDe serDe) {
            this.pastureListener = pastureListener;
            this.serDe = serDe;
        }

        @Override
        public synchronized boolean setPopulation(Breed[] population, long version) {
            //Ignore outdated non-static version
            if(version >=0 && version <= assignedVersion){
                return false;
            }

            Supplier> latest = memoize(() -> serDe.serialize(Arrays.asList(population)));
            if(this.snapshot == null
                    || version >= 0 && version > this.snapshot.getVersion()
                    || version < 0 && !this.snapshot.getSheep().equals(latest.get())){
                this.latest = new Population(latest.get(), version);
                //call rebalance on new population for leader only
                if(snapshot != null){
                    this.snapshot = null;
                    pastureShepherd.setNeedsReconfigRebalance();
                    return true;
                }
            }

            return false;
        }

        @Override
        public synchronized Population getPopulation() {
            if(snapshot != null){
                throw new IllegalStateException("Should be called only once on rebalance");
            }
            if(latest == null){
                throw new IllegalStateException("Herd was not initialized before rebalance");
            }

            snapshot = latest;
            latest = null;
            return snapshot;
        }

        @Override
        public synchronized void reset() {
            if(snapshot != null) {
                latest = snapshot;
                snapshot = null;
            }
        }

        @Override
        public synchronized void assigned(List population, long version, int generation, boolean isLeader) {
            this.pastureListener.assigned(serDe.deserialize(population), version, generation, isLeader);
            this.assignedVersion = version;
        }

        @Override
        public void cleanup() {
            this.pastureListener.cleanup();
        }

        @Override
        public Shepherd getShepherd() {
            return this;
        }

        @Override
        public void start() {
            pastureShepherd.start();
        }

        @Override
        public void close(Duration timeout) {
            pastureShepherd.stop(timeout.toMillis());
        }

        public void setPastureShepherd(PastureShepherd pastureShepherd) {
            this.pastureShepherd = pastureShepherd;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy