Search in sources :

Example 1 with DisableBackPressureOperator

use of io.reactivx.mantis.operators.DisableBackPressureOperator in project mantis by Netflix.

the class ObservableTrigger method groupTrigger.

private static <K, V> PushTrigger<KeyValuePair<K, V>> groupTrigger(final String name, final Observable<GroupedObservable<K, V>> o, final Action0 doOnComplete, final Action1<Throwable> doOnError, final long groupExpirySeconds, final Func1<K, byte[]> keyEncoder, final HashFunction hashFunction) {
    final AtomicReference<Subscription> subRef = new AtomicReference<>();
    final Gauge subscriptionActive;
    Metrics metrics = new Metrics.Builder().name("ObservableTrigger_" + name).addGauge("subscriptionActive").build();
    subscriptionActive = metrics.getGauge("subscriptionActive");
    Action1<MonitoredQueue<KeyValuePair<K, V>>> doOnStart = new Action1<MonitoredQueue<KeyValuePair<K, V>>>() {

        @Override
        public void call(final MonitoredQueue<KeyValuePair<K, V>> queue) {
            subRef.set(o.observeOn(Schedulers.computation()).doOnSubscribe(() -> {
                logger.info("Subscription is ACTIVE for observable trigger with name: " + name);
                subscriptionActive.set(1);
            }).doOnUnsubscribe(() -> {
                logger.info("Subscription is INACTIVE for observable trigger with name: " + name);
                subscriptionActive.set(0);
            }).flatMap((final GroupedObservable<K, V> group) -> {
                final byte[] keyBytes = keyEncoder.call(group.getKey());
                final long keyBytesHashed = hashFunction.computeHash(keyBytes);
                return group.timeout(groupExpirySeconds, TimeUnit.SECONDS, (Observable<? extends V>) Observable.empty()).lift(new DisableBackPressureOperator<V>()).buffer(250, TimeUnit.MILLISECONDS).filter((List<V> t1) -> t1 != null && !t1.isEmpty()).map((List<V> list) -> {
                    List<KeyValuePair<K, V>> keyPairList = new ArrayList<>(list.size());
                    for (V data : list) {
                        keyPairList.add(new KeyValuePair<K, V>(keyBytesHashed, keyBytes, data));
                    }
                    return keyPairList;
                });
            }).subscribe((List<KeyValuePair<K, V>> list) -> {
                for (KeyValuePair<K, V> data : list) {
                    queue.write(data);
                }
            }, (Throwable e) -> {
                logger.warn("Observable used to push data errored, on server with name: " + name, e);
                if (doOnError != null) {
                    doOnError.call(e);
                }
            }, () -> {
                logger.info("Observable used to push data completed, on server with name: " + name);
                if (doOnComplete != null) {
                    doOnComplete.call();
                }
            }));
        }
    };
    Action1<MonitoredQueue<KeyValuePair<K, V>>> doOnStop = new Action1<MonitoredQueue<KeyValuePair<K, V>>>() {

        @Override
        public void call(MonitoredQueue<KeyValuePair<K, V>> t1) {
            if (subRef.get() != null) {
                logger.warn("Connections from next stage has dropped to 0. Do not propagate unsubscribe");
            // subRef.get().unsubscribe();
            }
        }
    };
    return new PushTrigger<>(doOnStart, doOnStop, metrics);
}
Also used : DisableBackPressureOperator(io.reactivx.mantis.operators.DisableBackPressureOperator) Action1(rx.functions.Action1) ArrayList(java.util.ArrayList) AtomicReference(java.util.concurrent.atomic.AtomicReference) Gauge(io.mantisrx.common.metrics.Gauge) Metrics(io.mantisrx.common.metrics.Metrics) ArrayList(java.util.ArrayList) List(java.util.List) Subscription(rx.Subscription) GroupedObservable(rx.observables.GroupedObservable)

Example 2 with DisableBackPressureOperator

use of io.reactivx.mantis.operators.DisableBackPressureOperator in project mantis by Netflix.

the class ServeGroupedObservable method applySlottingSideEffectToObservable.

private void applySlottingSideEffectToObservable(Observable<Observable<GroupedObservable<String, V>>> o, final Observable<Integer> minConnectionsToSubscribe) {
    final AtomicInteger currentMinConnectionsToSubscribe = new AtomicInteger();
    minConnectionsToSubscribe.subscribe(new Action1<Integer>() {

        @Override
        public void call(Integer t1) {
            currentMinConnectionsToSubscribe.set(t1);
        }
    });
    Observable<Observable<List<Group<String, V>>>> listOfGroups = o.map(new Func1<Observable<GroupedObservable<String, V>>, Observable<List<Group<String, V>>>>() {

        @Override
        public Observable<List<Group<String, V>>> call(Observable<GroupedObservable<String, V>> og) {
            return og.flatMap(new Func1<GroupedObservable<String, V>, Observable<List<Group<String, V>>>>() {

                @Override
                public Observable<List<Group<String, V>>> call(final GroupedObservable<String, V> group) {
                    final byte[] keyBytes = keyEncoder.encode(group.getKey());
                    final String keyValue = group.getKey();
                    return group.doOnUnsubscribe(new Action0() {

                        @Override
                        public void call() {
                            // logger.info("Expiring group stage in serveGroupedObservable " + group.getKey());
                            groupsExpiredCounter.increment();
                        }
                    }).timeout(expiryInSecs, TimeUnit.SECONDS, (Observable<? extends V>) Observable.empty()).materialize().lift(new DisableBackPressureOperator<Notification<V>>()).buffer(groupBufferTimeMSec, TimeUnit.MILLISECONDS).filter(new Func1<List<Notification<V>>, Boolean>() {

                        @Override
                        public Boolean call(List<Notification<V>> t1) {
                            return t1 != null && !t1.isEmpty();
                        }
                    }).map(new Func1<List<Notification<V>>, List<Group<String, V>>>() {

                        @Override
                        public List<Group<String, V>> call(List<Notification<V>> notifications) {
                            List<Group<String, V>> groups = new ArrayList<>(notifications.size());
                            for (Notification<V> notification : notifications) {
                                groups.add(new Group<String, V>(keyValue, keyBytes, notification));
                            }
                            return groups;
                        }
                    });
                }
            });
        }
    });
    final Observable<List<Group<String, V>>> withSideEffects = Observable.merge(listOfGroups).doOnEach(new Observer<List<Group<String, V>>>() {

        @Override
        public void onCompleted() {
            slottingStrategy.completeAllConnections();
        }

        @Override
        public void onError(Throwable e) {
            e.printStackTrace();
            slottingStrategy.errorAllConnections(e);
        }

        @Override
        public void onNext(List<Group<String, V>> listOfGroups) {
            for (Group<String, V> group : listOfGroups) {
                slottingStrategy.writeOnSlot(group.getKeyBytes(), group);
            }
        }
    });
    final MutableReference<Subscription> subscriptionRef = new MutableReference<>();
    final AtomicInteger connectionCount = new AtomicInteger(0);
    final AtomicBoolean isSubscribed = new AtomicBoolean();
    slottingStrategy.registerDoOnEachConnectionAdded(new Action0() {

        @Override
        public void call() {
            Integer minNeeded = currentMinConnectionsToSubscribe.get();
            Integer current = connectionCount.incrementAndGet();
            if (current >= minNeeded) {
                if (isSubscribed.compareAndSet(false, true)) {
                    logger.info("MinConnectionsToSubscribe: " + minNeeded + ", has been met, subscribing to observable, current connection count: " + current);
                    subscriptionRef.setValue(withSideEffects.subscribe());
                }
            } else {
                logger.info("MinConnectionsToSubscribe: " + minNeeded + ", has NOT been met, current connection count: " + current);
            }
        }
    });
    slottingStrategy.registerDoAfterLastConnectionRemoved(new Action0() {

        @Override
        public void call() {
            subscriptionRef.getValue().unsubscribe();
            logger.info("All connections deregistered, unsubscribed to observable, resetting current connection count: 0");
            connectionCount.set(0);
            isSubscribed.set(false);
        }
    });
}
Also used : Notification(rx.Notification) ArrayList(java.util.ArrayList) List(java.util.List) Func1(rx.functions.Func1) Subscription(rx.Subscription) Action0(rx.functions.Action0) DisableBackPressureOperator(io.reactivx.mantis.operators.DisableBackPressureOperator) Observable(rx.Observable) GroupedObservable(rx.observables.GroupedObservable) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) GroupedObservable(rx.observables.GroupedObservable)

Example 3 with DisableBackPressureOperator

use of io.reactivx.mantis.operators.DisableBackPressureOperator in project mantis by Netflix.

the class ServerSentEventRequestHandler method handle.

@Override
public Observable<Void> handle(HttpServerRequest<ByteBuf> request, final HttpServerResponse<ServerSentEvent> response) {
    InetSocketAddress socketAddress = (InetSocketAddress) response.getChannel().remoteAddress();
    LOG.info("HTTP SSE connection received from " + socketAddress.getAddress() + ":" + socketAddress.getPort() + "  queryParams: " + request.getQueryParameters());
    final String socketAddrStr = socketAddress.getAddress().toString();
    final WritableEndpoint<String> sn = new WritableEndpoint<>(socketAddress.getHostString(), socketAddress.getPort(), Endpoint.uniqueHost(socketAddress.getHostString(), socketAddress.getPort(), null));
    final Map<String, List<String>> queryParameters = request.getQueryParameters();
    final SlotAssignmentManager<String> slotMgr = ssm.registerServer(sn, queryParameters);
    final AtomicLong lastResponseFlush = new AtomicLong();
    lastResponseFlush.set(-1);
    final AtomicLong lastResponseSent = new AtomicLong(-1);
    // copy reference, then apply request specific filters, sampling
    Observable<T> requestObservable = observableToServe;
    // decouple the observable on a separate thread and add backpressure handling
    // ServiceRegistry.INSTANCE.getPropertiesService().getStringValue("sse.decouple", "false");
    String decoupleSSE = "false";
    if ("true".equals(decoupleSSE)) {
        final BasicTag sockAddrTag = new BasicTag("sockAddr", Optional.ofNullable(socketAddrStr).orElse("none"));
        requestObservable = requestObservable.lift(new DropOperator<T>("outgoing_ServerSentEventRequestHandler", sockAddrTag)).observeOn(Schedulers.io());
    }
    response.getHeaders().set("Access-Control-Allow-Origin", "*");
    response.getHeaders().set("content-type", "text/event-stream");
    response.getHeaders().set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
    response.getHeaders().set("Pragma", "no-cache");
    response.flush();
    String uniqueClientId = socketAddrStr;
    if (queryParameters != null && queryParameters.containsKey(CLIENT_ID_PARAM)) {
        // enablePings
        uniqueClientId = queryParameters.get(CLIENT_ID_PARAM).get(0);
    }
    if (queryParameters != null && queryParameters.containsKey(FORMAT_PARAM)) {
        format = queryParameters.get(FORMAT_PARAM).get(0);
    }
    if (queryParameters != null && requestPreprocessor != null) {
        requestPreprocessor.call(queryParameters, context);
    }
    // apply sampling, milli, then seconds
    if (queryParameters != null && queryParameters.containsKey(SAMPLE_PARAM_MSEC)) {
        // apply sampling rate
        int samplingRate = Integer.parseInt(queryParameters.get(SAMPLE_PARAM_MSEC).get(0));
        requestObservable = requestObservable.sample(samplingRate, TimeUnit.MILLISECONDS);
    }
    if (queryParameters != null && queryParameters.containsKey(SAMPLE_PARAM)) {
        // apply sampling rate
        int samplingRate = Integer.parseInt(queryParameters.get(SAMPLE_PARAM).get(0));
        requestObservable = requestObservable.sample(samplingRate, TimeUnit.SECONDS);
    }
    if (queryParameters != null && queryParameters.containsKey(ENABLE_PINGS_PARAM)) {
        // enablePings
        String enablePings = queryParameters.get(ENABLE_PINGS_PARAM).get(0);
        if ("true".equalsIgnoreCase(enablePings)) {
            pingsEnabled = true;
        } else {
            pingsEnabled = false;
        }
    }
    if (queryParameters != null && queryParameters.containsKey("delay")) {
        // apply flush
        try {
            int flushInterval = Integer.parseInt(queryParameters.get("delay").get(0));
            if (flushInterval >= 50) {
                flushIntervalMillis = flushInterval;
            } else {
                LOG.warn("delay parameter too small " + flushInterval + " min. is 100");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    final byte[] delimiter = queryParameters != null && queryParameters.containsKey(MantisSSEConstants.MANTIS_COMPRESSION_DELIMITER) && queryParameters.get(MantisSSEConstants.MANTIS_COMPRESSION_DELIMITER).get(0) != null ? queryParameters.get(MantisSSEConstants.MANTIS_COMPRESSION_DELIMITER).get(0).getBytes() : null;
    Tag[] tags = new Tag[2];
    final String clientId = Optional.ofNullable(uniqueClientId).orElse("none");
    final String sockAddr = Optional.ofNullable(socketAddrStr).orElse("none");
    tags[0] = new BasicTag("clientId", clientId);
    tags[1] = new BasicTag("sockAddr", sockAddr);
    Metrics sseSinkMetrics = new Metrics.Builder().id("ServerSentEventRequestHandler", tags).addCounter("processedCounter").addCounter("pingCounter").addCounter("errorCounter").addCounter("droppedCounter").addCounter("flushCounter").build();
    final Counter msgProcessedCounter = sseSinkMetrics.getCounter("processedCounter");
    final Counter pingCounter = sseSinkMetrics.getCounter("pingCounter");
    final Counter errorCounter = sseSinkMetrics.getCounter("errorCounter");
    final Counter droppedWrites = sseSinkMetrics.getCounter("droppedCounter");
    final Counter flushCounter = sseSinkMetrics.getCounter("flushCounter");
    // get predicate, defaults to return true for all T
    Func1<T, Boolean> filterFunction = new Func1<T, Boolean>() {

        @Override
        public Boolean call(T t1) {
            return true;
        }
    };
    if (queryParameters != null && predicate != null) {
        filterFunction = predicate.getPredicate().call(queryParameters);
    }
    final Subscription timerSubscription = Observable.interval(1, TimeUnit.SECONDS).doOnNext(new Action1<Long>() {

        @Override
        public void call(Long t1) {
            long currentTime = System.currentTimeMillis();
            if (pingsEnabled && (lastResponseSent.get() == -1 || currentTime > lastResponseSent.get() + PING_INTERVAL)) {
                pingCounter.increment();
                response.writeStringAndFlush(PING);
                lastResponseSent.set(currentTime);
            }
        }
    }).subscribe();
    return requestObservable.filter(filterFunction).map(encoder).lift(new DisableBackPressureOperator<String>()).buffer(flushIntervalMillis, TimeUnit.MILLISECONDS).flatMap(new Func1<List<String>, Observable<Void>>() {

        @Override
        public Observable<Void> call(List<String> valueList) {
            if (response.isCloseIssued() || !response.getChannel().isActive()) {
                LOG.info("Client closed detected, throwing closed channel exception");
                return Observable.error(new ClosedChannelException());
            }
            List<String> filteredList = valueList.stream().filter(e -> {
                return slotMgr.filter(sn, e.getBytes());
            }).collect(Collectors.toList());
            if (response.getChannel().isWritable()) {
                flushCounter.increment();
                if (format.equals(BINARY_FORMAT)) {
                    boolean useSnappy = true;
                    try {
                        String compressedList = delimiter == null ? CompressionUtils.compressAndBase64Encode(filteredList, useSnappy) : CompressionUtils.compressAndBase64Encode(filteredList, useSnappy, delimiter);
                        StringBuilder sb = new StringBuilder(3);
                        sb.append(SSE_DATA_PREFIX);
                        sb.append(compressedList);
                        sb.append(TWO_NEWLINES);
                        msgProcessedCounter.increment(valueList.size());
                        lastResponseSent.set(System.currentTimeMillis());
                        return response.writeStringAndFlush(sb.toString());
                    } catch (Exception e) {
                        LOG.warn("Could not compress data" + e.getMessage());
                        droppedWrites.increment(valueList.size());
                        return Observable.empty();
                    }
                } else {
                    int noOfMsgs = 0;
                    StringBuilder sb = new StringBuilder(valueList.size() * 3);
                    for (String s : filteredList) {
                        sb.append(SSE_DATA_PREFIX);
                        sb.append(s);
                        sb.append(TWO_NEWLINES);
                        noOfMsgs++;
                    }
                    msgProcessedCounter.increment(noOfMsgs);
                    lastResponseSent.set(System.currentTimeMillis());
                    return response.writeStringAndFlush(sb.toString());
                }
            } else {
                // 
                droppedWrites.increment(filteredList.size());
            }
            return Observable.empty();
        }
    }).onErrorResumeNext(new Func1<Throwable, Observable<? extends Void>>() {

        @Override
        public Observable<? extends Void> call(Throwable throwable) {
            Throwable cause = throwable.getCause();
            // ignore closed channel exceptions, this is
            // when the connection was closed on the client
            // side without informing the server
            errorCounter.increment();
            if (cause != null && !(cause instanceof ClosedChannelException)) {
                LOG.warn("Error detected in SSE sink", cause);
                if (errorEncoder != null) {
                    // write error out on connection
                    // response.writeAndFlush(errorEncoder.call(throwable));
                    ByteBuf errType = response.getAllocator().buffer().writeBytes("error: ".getBytes());
                    ByteBuf errRes = response.getAllocator().buffer().writeBytes((errorEncoder.call(throwable)).getBytes());
                    response.writeAndFlush(ServerSentEvent.withEventType(errType, errRes));
                }
                throwable.printStackTrace();
            }
            if (requestPostprocessor != null && queryParameters != null) {
                requestPostprocessor.call(queryParameters, context);
            }
            ssm.deregisterServer(sn, queryParameters);
            timerSubscription.unsubscribe();
            return Observable.error(throwable);
        }
    });
}
Also used : Predicate(io.mantisrx.runtime.sink.predicate.Predicate) DisableBackPressureOperator(io.reactivx.mantis.operators.DisableBackPressureOperator) ServerSentEvent(mantis.io.reactivex.netty.protocol.http.sse.ServerSentEvent) LoggerFactory(org.slf4j.LoggerFactory) Action1(rx.functions.Action1) DropOperator(io.reactivx.mantis.operators.DropOperator) HttpServerResponse(mantis.io.reactivex.netty.protocol.http.server.HttpServerResponse) Observable(rx.Observable) Func1(rx.functions.Func1) Func2(rx.functions.Func2) ByteBuf(io.netty.buffer.ByteBuf) Map(java.util.Map) Schedulers(rx.schedulers.Schedulers) RequestHandler(mantis.io.reactivex.netty.protocol.http.server.RequestHandler) BasicTag(com.netflix.spectator.api.BasicTag) Metrics(io.mantisrx.common.metrics.Metrics) Counter(io.mantisrx.common.metrics.Counter) Logger(org.slf4j.Logger) Tag(com.netflix.spectator.api.Tag) HashFunctions(io.mantisrx.common.network.HashFunctions) Endpoint(io.mantisrx.common.network.Endpoint) ClosedChannelException(java.nio.channels.ClosedChannelException) WritableEndpoint(io.mantisrx.common.network.WritableEndpoint) Context(io.mantisrx.runtime.Context) InetSocketAddress(java.net.InetSocketAddress) Collectors(java.util.stream.Collectors) TimeUnit(java.util.concurrent.TimeUnit) AtomicLong(java.util.concurrent.atomic.AtomicLong) List(java.util.List) CompressionUtils(io.mantisrx.common.compression.CompressionUtils) SlotAssignmentManager(io.mantisrx.common.network.ServerSlotManager.SlotAssignmentManager) Optional(java.util.Optional) ServerSlotManager(io.mantisrx.common.network.ServerSlotManager) MantisSSEConstants(com.mantisrx.common.utils.MantisSSEConstants) HttpServerRequest(mantis.io.reactivex.netty.protocol.http.server.HttpServerRequest) Subscription(rx.Subscription) InetSocketAddress(java.net.InetSocketAddress) ByteBuf(io.netty.buffer.ByteBuf) BasicTag(com.netflix.spectator.api.BasicTag) Metrics(io.mantisrx.common.metrics.Metrics) Counter(io.mantisrx.common.metrics.Counter) List(java.util.List) Func1(rx.functions.Func1) Subscription(rx.Subscription) ClosedChannelException(java.nio.channels.ClosedChannelException) WritableEndpoint(io.mantisrx.common.network.WritableEndpoint) DisableBackPressureOperator(io.reactivx.mantis.operators.DisableBackPressureOperator) Action1(rx.functions.Action1) Endpoint(io.mantisrx.common.network.Endpoint) WritableEndpoint(io.mantisrx.common.network.WritableEndpoint) ClosedChannelException(java.nio.channels.ClosedChannelException) Observable(rx.Observable) AtomicLong(java.util.concurrent.atomic.AtomicLong) AtomicLong(java.util.concurrent.atomic.AtomicLong) BasicTag(com.netflix.spectator.api.BasicTag) Tag(com.netflix.spectator.api.Tag)

Example 4 with DisableBackPressureOperator

use of io.reactivx.mantis.operators.DisableBackPressureOperator in project mantis by Netflix.

the class RemoteObservableConnectionHandler method serveNestedObservable.

@SuppressWarnings({ "unchecked", "rawtypes" })
private <T> Subscription serveNestedObservable(final Observable<T> observable, final ObservableConnection<RemoteRxEvent, List<RemoteRxEvent>> connection, final RemoteRxEvent event, final Func1<Map<String, String>, Func1<T, Boolean>> filterFunction, final Encoder<T> encoder, final ServeNestedObservable<Observable<T>> serveConfig, final WritableEndpoint<Observable<T>> endpoint) {
    final MutableReference<Subscription> subReference = new MutableReference<>();
    subReference.setValue(observable.filter(filterFunction.call(event.getSubscribeParameters())).doOnCompleted(new Action0() {

        @Override
        public void call() {
            logger.info("OnCompleted recieved in serveNestedObservable, sending to client.");
        }
    }).doOnError(new Action1<Throwable>() {

        @Override
        public void call(Throwable t1) {
            logger.info("OnError received in serveNestedObservable, sending to client: ", t1);
        }
    }).map(new Func1<T, byte[]>() {

        @Override
        public byte[] call(T t1) {
            return encoder.encode(t1);
        }
    }).materialize().map(new Func1<Notification<byte[]>, RemoteRxEvent>() {

        @Override
        public RemoteRxEvent call(Notification<byte[]> notification) {
            if (notification.getKind() == Notification.Kind.OnNext) {
                return RemoteRxEvent.next(event.getName(), notification.getValue());
            } else if (notification.getKind() == Notification.Kind.OnError) {
                return RemoteRxEvent.error(event.getName(), RemoteObservable.fromThrowableToBytes(notification.getThrowable()));
            } else if (notification.getKind() == Notification.Kind.OnCompleted) {
                return RemoteRxEvent.completed(event.getName());
            } else {
                throw new RuntimeException("Unsupported notification kind: " + notification.getKind());
            }
        }
    }).lift(new DisableBackPressureOperator<RemoteRxEvent>()).buffer(writeBufferTimeMSec, TimeUnit.MILLISECONDS).filter(new Func1<List<RemoteRxEvent>, Boolean>() {

        @Override
        public Boolean call(List<RemoteRxEvent> t1) {
            return t1 != null && !t1.isEmpty();
        }
    }).filter(new Func1<List<RemoteRxEvent>, Boolean>() {

        @Override
        public Boolean call(List<RemoteRxEvent> t1) {
            return t1 != null && !t1.isEmpty();
        }
    }).subscribe(new WriteBytesObserver(connection, subReference, serverMetrics, serveConfig.getSlottingStrategy(), endpoint)));
    return subReference.getValue();
}
Also used : Action0(rx.functions.Action0) DisableBackPressureOperator(io.reactivx.mantis.operators.DisableBackPressureOperator) Action1(rx.functions.Action1) Notification(rx.Notification) ArrayList(java.util.ArrayList) List(java.util.List) Subscription(rx.Subscription) Func1(rx.functions.Func1)

Aggregations

DisableBackPressureOperator (io.reactivx.mantis.operators.DisableBackPressureOperator)4 List (java.util.List)4 Subscription (rx.Subscription)4 ArrayList (java.util.ArrayList)3 Action1 (rx.functions.Action1)3 Func1 (rx.functions.Func1)3 Metrics (io.mantisrx.common.metrics.Metrics)2 Notification (rx.Notification)2 Observable (rx.Observable)2 Action0 (rx.functions.Action0)2 GroupedObservable (rx.observables.GroupedObservable)2 MantisSSEConstants (com.mantisrx.common.utils.MantisSSEConstants)1 BasicTag (com.netflix.spectator.api.BasicTag)1 Tag (com.netflix.spectator.api.Tag)1 CompressionUtils (io.mantisrx.common.compression.CompressionUtils)1 Counter (io.mantisrx.common.metrics.Counter)1 Gauge (io.mantisrx.common.metrics.Gauge)1 Endpoint (io.mantisrx.common.network.Endpoint)1 HashFunctions (io.mantisrx.common.network.HashFunctions)1 ServerSlotManager (io.mantisrx.common.network.ServerSlotManager)1