Search in sources :

Example 1 with Counter

use of io.mantisrx.common.metrics.Counter in project mantis by Netflix.

the class SseWorkerConnectionTest method testStreamContentDrops.

@Test
public void testStreamContentDrops() throws Exception {
    SpectatorRegistryFactory.setRegistry(new DefaultRegistry());
    String metricGroupString = "testmetric";
    MetricGroupId metricGroupId = new MetricGroupId(metricGroupString);
    SseWorkerConnection workerConnection = new SseWorkerConnection("connection_type", "hostname", 80, b -> {
    }, b -> {
    }, t -> {
    }, 600, false, new CopyOnWriteArraySet<>(), 1, null, true, metricGroupId);
    HttpClientResponse<ServerSentEvent> response = mock(HttpClientResponse.class);
    TestScheduler testScheduler = Schedulers.test();
    // Events are just "0", "1", "2", ...
    Observable<ServerSentEvent> contentObs = Observable.interval(1, TimeUnit.SECONDS, testScheduler).map(t -> new ServerSentEvent(Unpooled.copiedBuffer(Long.toString(t), Charset.defaultCharset())));
    when(response.getContent()).thenReturn(contentObs);
    TestSubscriber<MantisServerSentEvent> subscriber = new TestSubscriber<>(1);
    workerConnection.streamContent(response, b -> {
    }, 600, "delimiter").subscribeOn(testScheduler).subscribe(subscriber);
    testScheduler.advanceTimeBy(100, TimeUnit.SECONDS);
    subscriber.assertValueCount(1);
    List<MantisServerSentEvent> events = subscriber.getOnNextEvents();
    assertEquals("0", events.get(0).getEventAsString());
    Metrics metrics = MetricsRegistry.getInstance().getMetric(metricGroupId);
    Counter onNextCounter = metrics.getCounter(DropOperator.Counters.onNext.toString());
    Counter droppedCounter = metrics.getCounter(DropOperator.Counters.dropped.toString());
    logger.info("next: {}", onNextCounter.value());
    logger.info("drop: {}", droppedCounter.value());
    assertTrue(onNextCounter.value() < 10);
    assertTrue(droppedCounter.value() > 90);
}
Also used : ServerSentEvent(mantis.io.reactivex.netty.protocol.http.sse.ServerSentEvent) MantisServerSentEvent(io.mantisrx.common.MantisServerSentEvent) Metrics(io.mantisrx.common.metrics.Metrics) Counter(io.mantisrx.common.metrics.Counter) MantisServerSentEvent(io.mantisrx.common.MantisServerSentEvent) DefaultRegistry(com.netflix.spectator.api.DefaultRegistry) TestSubscriber(rx.observers.TestSubscriber) MetricGroupId(io.mantisrx.common.metrics.spectator.MetricGroupId) TestScheduler(rx.schedulers.TestScheduler) Test(org.junit.Test)

Example 2 with Counter

use of io.mantisrx.common.metrics.Counter in project mantis by Netflix.

the class PushServerSse method createServer.

@Override
public RxServer<?, ?> createServer() {
    RxServer<HttpServerRequest<String>, HttpServerResponse<ServerSentEvent>> server = RxNetty.newHttpServerBuilder(port, new RequestHandler<String, ServerSentEvent>() {

        @Override
        public Observable<Void> handle(HttpServerRequest<String> request, final HttpServerResponse<ServerSentEvent> response) {
            final Map<String, List<String>> queryParameters = request.getQueryParameters();
            final Counter sseProcessedCounter;
            final Counter sseDroppedCounter;
            // heartbeat state
            boolean enableHeartbeats = false;
            boolean enableBinaryOutput = false;
            final AtomicLong heartBeatReadIdleSec = new AtomicLong(2);
            SerializedSubject<String, String> metaMsgSubject = PublishSubject.<String>create().toSerialized();
            final AtomicLong metaMessagesFreqMSec = new AtomicLong(1000);
            boolean enableMetaMessages = false;
            final AtomicLong lastWriteTime = new AtomicLong();
            Subscription heartbeatSubscription = null;
            Subscription metaMsgSubscription = null;
            // sample state
            boolean enableSampling = false;
            long samplingTimeMsec = 0;
            // client state
            String groupId = null;
            String slotId = null;
            String id = null;
            Func1<T, Boolean> predicateFunction = null;
            if (predicate != null) {
                predicateFunction = predicate.call(queryParameters);
            }
            byte[] delimiter = CompressionUtils.MANTIS_SSE_DELIMITER_BINARY;
            if (queryParameters != null && !queryParameters.isEmpty()) {
                if (queryParameters.containsKey(MantisSSEConstants.ID)) {
                    id = queryParameters.get(MantisSSEConstants.ID).get(0);
                }
                if (queryParameters.containsKey(MantisSSEConstants.SLOT_ID)) {
                    slotId = queryParameters.get(MantisSSEConstants.SLOT_ID).get(0);
                }
                // support groupId and clientId for grouping
                if (queryParameters.containsKey(MantisSSEConstants.GROUP_ID)) {
                    groupId = queryParameters.get(MantisSSEConstants.GROUP_ID).get(0);
                }
                if (queryParameters.containsKey(MantisSSEConstants.CLIENT_ID)) {
                    groupId = queryParameters.get(MantisSSEConstants.CLIENT_ID).get(0);
                }
                if (queryParameters.containsKey(MantisSSEConstants.HEARTBEAT_SEC)) {
                    heartBeatReadIdleSec.set(Long.parseLong(queryParameters.get(MantisSSEConstants.HEARTBEAT_SEC).get(0)));
                    if (heartBeatReadIdleSec.get() < 1) {
                        throw new IllegalArgumentException("Sampling rate too low: " + samplingTimeMsec);
                    }
                    enableHeartbeats = true;
                }
                if (queryParameters != null && queryParameters.containsKey(MantisSSEConstants.MANTIS_ENABLE_COMPRESSION)) {
                    String enableBinaryOutputStr = queryParameters.get(MantisSSEConstants.MANTIS_ENABLE_COMPRESSION).get(0);
                    if ("true".equalsIgnoreCase(enableBinaryOutputStr)) {
                        logger.info("Binary compression requested");
                        enableBinaryOutput = true;
                    }
                }
                if (queryParameters.containsKey(MantisSSEConstants.ENABLE_PINGS)) {
                    String enablePings = queryParameters.get(MantisSSEConstants.ENABLE_PINGS).get(0);
                    if ("true".equalsIgnoreCase(enablePings)) {
                        enableHeartbeats = true;
                    }
                }
                if (queryParameters.containsKey(MantisSSEConstants.ENABLE_META_MESSAGES)) {
                    String enableMetaMessagesStr = queryParameters.get(MantisSSEConstants.ENABLE_META_MESSAGES).get(0);
                    if ("true".equalsIgnoreCase(enableMetaMessagesStr)) {
                        enableMetaMessages = true;
                    }
                }
                if (queryParameters.containsKey(MantisSSEConstants.META_MESSAGES_SEC)) {
                    metaMessagesFreqMSec.set(Long.parseLong(queryParameters.get(MantisSSEConstants.META_MESSAGES_SEC).get(0)));
                    if (metaMessagesFreqMSec.get() < 250) {
                        throw new IllegalArgumentException("Meta message frequence rate too low: " + metaMessagesFreqMSec.get());
                    }
                    enableMetaMessages = true;
                }
                if (queryParameters.containsKey(MantisSSEConstants.SAMPLE)) {
                    samplingTimeMsec = Long.parseLong(queryParameters.get(MantisSSEConstants.SAMPLE).get(0)) * 1000;
                    if (samplingTimeMsec < 50) {
                        throw new IllegalArgumentException("Sampling rate too low: " + samplingTimeMsec);
                    }
                    enableSampling = true;
                }
                if (queryParameters.containsKey(MantisSSEConstants.SAMPLE_M_SEC)) {
                    samplingTimeMsec = Long.parseLong(queryParameters.get(MantisSSEConstants.SAMPLE_M_SEC).get(0));
                    if (samplingTimeMsec < 50) {
                        throw new IllegalArgumentException("Sampling rate too low: " + samplingTimeMsec);
                    }
                    enableSampling = true;
                }
                if (queryParameters.containsKey(MantisSSEConstants.MANTIS_COMPRESSION_DELIMITER)) {
                    String rawDelimiter = queryParameters.get(MantisSSEConstants.MANTIS_COMPRESSION_DELIMITER).get(0);
                    if (rawDelimiter != null && !rawDelimiter.isEmpty()) {
                        delimiter = rawDelimiter.getBytes();
                    }
                }
                if (queryParameters.containsKey(MantisSSEConstants.MQL)) {
                    String query = queryParameters.get(MantisSSEConstants.MQL).get(0);
                    if ((Boolean) mqlParses.invoke(query)) {
                        Query q = (Query) mqlMakeQuery.invoke(groupId, query);
                        predicateFunction = (T datum) -> datum instanceof Map ? q.matches((Map) datum) : true;
                    }
                }
            }
            InetSocketAddress socketAddress = (InetSocketAddress) response.getChannel().remoteAddress();
            Metrics metrics;
            if (groupId == null) {
                String address = socketAddress.getAddress().toString();
                metrics = registerSseMetrics(address, address);
            } else {
                metrics = registerSseMetrics(groupId, socketAddress.getAddress().toString());
            }
            sseProcessedCounter = metrics.getCounter(PROCESSED_COUNTER_METRIC_NAME);
            sseDroppedCounter = metrics.getCounter(DROPPED_COUNTER_METRIC_NAME);
            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();
            if (queryParameters != null && requestPreprocessor != null) {
                requestPreprocessor.call(queryParameters, processorState);
            }
            if (enableMetaMessages && metaMessagesFreqMSec.get() > 0) {
                logger.info("Enabling Meta messages, interval : " + metaMessagesFreqMSec.get() + " ms");
                metaMsgSubscription = metaMsgSubject.throttleLast(metaMessagesFreqMSec.get(), TimeUnit.MILLISECONDS).doOnNext((String t) -> {
                    if (t != null && !t.isEmpty()) {
                        long currentTime = System.currentTimeMillis();
                        ByteBuf data = response.getAllocator().buffer().writeBytes(t.getBytes());
                        response.writeAndFlush(new ServerSentEvent(data));
                        lastWriteTime.set(currentTime);
                    }
                }).subscribe();
            }
            if (enableHeartbeats && heartBeatReadIdleSec.get() > 0) {
                logger.info("Enabling hearts, interval: " + heartBeatReadIdleSec);
                heartbeatSubscription = Observable.interval(2, heartBeatReadIdleSec.get(), TimeUnit.SECONDS).doOnNext((Long t1) -> {
                    long currentTime = System.currentTimeMillis();
                    long diff = (currentTime - lastWriteTime.get()) / 1000;
                    if (diff > heartBeatReadIdleSec.get()) {
                        ByteBuf data = response.getAllocator().buffer().writeBytes("ping".getBytes());
                        response.writeAndFlush(new ServerSentEvent(data));
                        lastWriteTime.set(currentTime);
                    }
                }).subscribe();
            }
            Action0 connectionClosedCallback = null;
            if (queryParameters != null && requestPostprocessor != null) {
                connectionClosedCallback = new Action0() {

                    @Override
                    public void call() {
                        requestPostprocessor.call(queryParameters, processorState);
                    }
                };
            }
            class SubscribeCallback implements Action0 {

                @Override
                public void call() {
                    if (queryParameters != null && subscribeProcessor != null) {
                        subscribeProcessor.call(queryParameters, processorState);
                    }
                }
            }
            return manageConnectionWithCompression(response, socketAddress.getHostString(), socketAddress.getPort(), groupId, slotId, id, lastWriteTime, enableHeartbeats, heartbeatSubscription, enableSampling, samplingTimeMsec, metaMsgSubject, metaMsgSubscription, predicateFunction, connectionClosedCallback, sseProcessedCounter, sseDroppedCounter, new SubscribeCallback(), enableBinaryOutput, true, delimiter);
        }
    }).pipelineConfigurator(PipelineConfigurators.serveSseConfigurator()).channelOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 1024, 5 * 1024 * 1024)).build();
    return server;
}
Also used : Query(io.mantisrx.mql.jvm.core.Query) InetSocketAddress(java.net.InetSocketAddress) ServerSentEvent(mantis.io.reactivex.netty.protocol.http.sse.ServerSentEvent) ByteBuf(io.netty.buffer.ByteBuf) Metrics(io.mantisrx.common.metrics.Metrics) Counter(io.mantisrx.common.metrics.Counter) HttpServerResponse(mantis.io.reactivex.netty.protocol.http.server.HttpServerResponse) List(java.util.List) WriteBufferWaterMark(io.netty.channel.WriteBufferWaterMark) Subscription(rx.Subscription) Action0(rx.functions.Action0) HttpServerRequest(mantis.io.reactivex.netty.protocol.http.server.HttpServerRequest) AtomicLong(java.util.concurrent.atomic.AtomicLong) RequestHandler(mantis.io.reactivex.netty.protocol.http.server.RequestHandler) AtomicLong(java.util.concurrent.atomic.AtomicLong) Map(java.util.Map)

Example 3 with Counter

use of io.mantisrx.common.metrics.Counter 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 Counter

use of io.mantisrx.common.metrics.Counter in project mantis by Netflix.

the class LegacyTcpPushServer method createServer.

@Override
public RxServer<?, ?> createServer() {
    RxServer<RemoteRxEvent, RemoteRxEvent> server = RxNetty.newTcpServerBuilder(port, new ConnectionHandler<RemoteRxEvent, RemoteRxEvent>() {

        @Override
        public Observable<Void> handle(final ObservableConnection<RemoteRxEvent, RemoteRxEvent> newConnection) {
            final InetSocketAddress socketAddress = (InetSocketAddress) newConnection.getChannel().remoteAddress();
            // extract groupId, id, predicate from incoming byte[]
            return newConnection.getInput().flatMap(new Func1<RemoteRxEvent, Observable<Void>>() {

                @Override
                public Observable<Void> call(RemoteRxEvent incomingRequest) {
                    if (incomingRequest.getType() == RemoteRxEvent.Type.subscribed) {
                        Map<String, String> params = incomingRequest.getSubscribeParameters();
                        // client state
                        String id = null;
                        String slotId = null;
                        String groupId = null;
                        // sample state
                        boolean enableSampling = false;
                        long samplingTimeMsec = 0;
                        // predicate state
                        Map<String, List<String>> predicateParams = null;
                        if (params != null && !params.isEmpty()) {
                            predicateParams = new HashMap<String, List<String>>();
                            for (Entry<String, String> entry : params.entrySet()) {
                                List<String> values = new LinkedList<>();
                                values.add(entry.getValue());
                                predicateParams.put(entry.getKey(), values);
                            }
                            if (params.containsKey("id")) {
                                id = params.get("id");
                            }
                            if (params.containsKey("slotId")) {
                                slotId = params.get("slotId");
                            }
                            if (params.containsKey("groupId")) {
                                groupId = params.get("groupId");
                            }
                            if (params.containsKey("sample")) {
                                samplingTimeMsec = Long.parseLong(params.get("sample")) * 1000;
                                if (samplingTimeMsec < 50) {
                                    throw new IllegalArgumentException("Sampling rate too low: " + samplingTimeMsec);
                                }
                                enableSampling = true;
                            }
                            if (params.containsKey("sampleMSec")) {
                                samplingTimeMsec = Long.parseLong(params.get("sampleMSec"));
                                if (samplingTimeMsec < 50) {
                                    throw new IllegalArgumentException("Sampling rate too low: " + samplingTimeMsec);
                                }
                                enableSampling = true;
                            }
                        }
                        Func1<T, Boolean> predicateFunction = null;
                        if (predicate != null) {
                            predicateFunction = predicate.call(predicateParams);
                        }
                        // support legacy metrics per connection
                        Metrics sseSinkMetrics = new Metrics.Builder().name("DropOperator_outgoing_subject_" + slotId).addCounter("onNext").addCounter("dropped").build();
                        sseSinkMetrics = metricsRegistry.registerAndGet(sseSinkMetrics);
                        Counter legacyMsgProcessedCounter = sseSinkMetrics.getCounter("onNext");
                        Counter legacyDroppedWrites = sseSinkMetrics.getCounter("dropped");
                        return manageConnection(newConnection, socketAddress.getHostString(), socketAddress.getPort(), groupId, slotId, id, null, false, null, enableSampling, samplingTimeMsec, predicateFunction, null, legacyMsgProcessedCounter, legacyDroppedWrites, null);
                    }
                    return null;
                }
            });
        }
    }).pipelineConfigurator(new PipelineConfiguratorComposite<RemoteRxEvent, RemoteRxEvent>(new PipelineConfigurator<RemoteRxEvent, RemoteRxEvent>() {

        @Override
        public void configureNewPipeline(ChannelPipeline pipeline) {
            // pipeline.addLast(new LoggingHandler(LogLevel.ERROR)); // uncomment to enable debug logging
            pipeline.addLast("idleStateHandler", new IdleStateHandler(10, 2, 0));
            pipeline.addLast("heartbeat", new HeartbeatHandler());
            pipeline.addLast("gzipInflater", new JdkZlibEncoder(ZlibWrapper.GZIP));
            pipeline.addLast("gzipDeflater", new JdkZlibDecoder(ZlibWrapper.GZIP));
            // 4 bytes to encode length
            pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
            // max frame = half MB
            pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(5242880, 0, 4, 0, 4));
        }
    }, new LegacyTcpPipelineConfigurator(name))).channelOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 1024, 5 * 1024 * 1024)).build();
    return server;
}
Also used : HashMap(java.util.HashMap) InetSocketAddress(java.net.InetSocketAddress) LengthFieldPrepender(io.netty.handler.codec.LengthFieldPrepender) Entry(java.util.Map.Entry) Metrics(io.mantisrx.common.metrics.Metrics) Counter(io.mantisrx.common.metrics.Counter) LinkedList(java.util.LinkedList) List(java.util.List) WriteBufferWaterMark(io.netty.channel.WriteBufferWaterMark) Func1(rx.functions.Func1) JdkZlibEncoder(io.netty.handler.codec.compression.JdkZlibEncoder) LengthFieldBasedFrameDecoder(io.netty.handler.codec.LengthFieldBasedFrameDecoder) ObservableConnection(mantis.io.reactivex.netty.channel.ObservableConnection) Observable(rx.Observable) ChannelPipeline(io.netty.channel.ChannelPipeline) PipelineConfigurator(mantis.io.reactivex.netty.pipeline.PipelineConfigurator) ConnectionHandler(mantis.io.reactivex.netty.channel.ConnectionHandler) JdkZlibDecoder(io.netty.handler.codec.compression.JdkZlibDecoder) IdleStateHandler(io.netty.handler.timeout.IdleStateHandler) HashMap(java.util.HashMap) Map(java.util.Map)

Example 5 with Counter

use of io.mantisrx.common.metrics.Counter in project mantis by Netflix.

the class SseWorkerConnection method hasDataDrop.

private boolean hasDataDrop() {
    final Collection<Metrics> metrics = MetricsRegistry.getInstance().getMetrics(metricNamePrefix);
    long totalDataDrop = 0L;
    if (metrics != null && !metrics.isEmpty()) {
        // logger.info("Got " + metrics.size() + " metrics for DropOperator");
        for (Metrics m : metrics) {
            final Counter dropped = m.getCounter("" + DropOperator.Counters.dropped);
            final Counter onNext = m.getCounter("" + DropOperator.Counters.onNext);
            if (dropped != null)
                totalDataDrop += dropped.value();
        }
    }
    if (totalDataDrop > lastDataDropValue) {
        lastDataDropValue = totalDataDrop;
        return true;
    }
    return false;
}
Also used : Metrics(io.mantisrx.common.metrics.Metrics) Counter(io.mantisrx.common.metrics.Counter)

Aggregations

Counter (io.mantisrx.common.metrics.Counter)6 Metrics (io.mantisrx.common.metrics.Metrics)6 InetSocketAddress (java.net.InetSocketAddress)3 List (java.util.List)3 Map (java.util.Map)3 ByteBuf (io.netty.buffer.ByteBuf)2 WriteBufferWaterMark (io.netty.channel.WriteBufferWaterMark)2 AtomicLong (java.util.concurrent.atomic.AtomicLong)2 ServerSentEvent (mantis.io.reactivex.netty.protocol.http.sse.ServerSentEvent)2 Observable (rx.Observable)2 Func1 (rx.functions.Func1)2 MantisSSEConstants (com.mantisrx.common.utils.MantisSSEConstants)1 BasicTag (com.netflix.spectator.api.BasicTag)1 DefaultRegistry (com.netflix.spectator.api.DefaultRegistry)1 Tag (com.netflix.spectator.api.Tag)1 MantisServerSentEvent (io.mantisrx.common.MantisServerSentEvent)1 CompressionUtils (io.mantisrx.common.compression.CompressionUtils)1 MetricGroupId (io.mantisrx.common.metrics.spectator.MetricGroupId)1 Endpoint (io.mantisrx.common.network.Endpoint)1 HashFunctions (io.mantisrx.common.network.HashFunctions)1