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

org.aksw.commons.rx.op.OperatorObserveThroughput Maven / Gradle / Ivy

There is a newer version: 0.9.9
Show newest version
package org.aksw.commons.rx.op;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;

import org.aksw.commons.rx.util.RxUtils;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

import io.reactivex.rxjava3.core.FlowableOperator;
import io.reactivex.rxjava3.core.FlowableSubscriber;
import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper;

/**
 * Operator that fires a callback every time it has seen a configurable number of items.
 *
 * @author raven
 *
 * @param 
 */
public class OperatorObserveThroughput
    implements FlowableOperator
{
    protected String name;
    protected long interval;

    public static class ThroughputEvent {
        public ThroughputEvent(long eventInterval, String name, long instanceId, double elapsedSeconds,
                long totalSeenItemCount) {
            super();
            this.eventInterval = eventInterval;
            this.name = name;
            this.instanceId = instanceId;
            this.elapsedSeconds = elapsedSeconds;
            this.totalSeenItemCount = totalSeenItemCount;
        }

        public long eventInterval;
        public String name;
        long instanceId;
        double elapsedSeconds;
        long totalSeenItemCount;
    }

    protected Consumer eventHandler;

    public static void defaultThroughputEventHandler(ThroughputEvent event) {
        System.err.println("On " + event.name + "-" + event.instanceId + " seen item count = " + event.totalSeenItemCount + " - throughput: " + (event.totalSeenItemCount / (event.elapsedSeconds)) + " items per second");
    }

    public static  OperatorObserveThroughput create(String name, long interval) {
        return new OperatorObserveThroughput<>(name, interval, OperatorObserveThroughput::defaultThroughputEventHandler);
    }

    public static  OperatorObserveThroughput create(String name, long interval, Consumer eventHandler) {
        return new OperatorObserveThroughput<>(name, interval, eventHandler);
    }

    public OperatorObserveThroughput(String name, long interval, Consumer eventHandler) {
        super();
        this.name = name;
        this.interval = interval;
        this.eventHandler = eventHandler;
    }

    @Override
    public Subscriber apply(Subscriber downstream) throws Exception {
        return new SubscriberImpl(downstream);
    }


    public class SubscriberImpl
        implements FlowableSubscriber, Subscription
    {
        protected Subscriber downstream;
        protected Subscription upstream;
        protected AtomicLong pending = new AtomicLong();

        int id;
        protected AtomicLong seenItems = new AtomicLong();
        long startTimeMillis;


        public SubscriberImpl(Subscriber downstream) {
            this.downstream = downstream;
        }

        @Override
        public void onSubscribe(Subscription s) {
            AtomicInteger n = RxUtils.nameMap.computeIfAbsent(name, k -> new AtomicInteger());
            id = n.incrementAndGet();
            startTimeMillis = System.currentTimeMillis();

            if (upstream != null) {
                s.cancel();
            } else {
                upstream = s;
                downstream.onSubscribe(this);
            }
        }

        @Override
        public void request(long n) {
            if (SubscriptionHelper.validate(n)) {
                pending.addAndGet(n);
                upstream.request(1);
            }
        }

        @Override
        public void onNext(T item) {
            long elapsed = System.currentTimeMillis() - startTimeMillis;

            long counter = seenItems.getAndIncrement();
            if(counter % interval == 0) {
                double totalElapsedSeconds = elapsed * 0.001;
                ThroughputEvent event = new ThroughputEvent(interval, name, id, totalElapsedSeconds, counter);
                eventHandler.accept(event);
            }

            downstream.onNext(item);
            long remaining = pending.decrementAndGet();
            if(remaining > 0) {
                upstream.request(1);
            }
        }

        @Override
        public void onComplete() {
            downstream.onComplete();
        }

        @Override
        public void onError(Throwable t) {
            downstream.onError(t);
        }

        @Override
        public void cancel() {
            upstream.cancel();
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy