Search in sources :

Example 1 with Query

use of io.mantisrx.mql.jvm.core.Query 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 2 with Query

use of io.mantisrx.mql.jvm.core.Query in project mantis by Netflix.

the class MQL method makeSupersetProjector.

@SuppressWarnings("unchecked")
public static Function<Map<String, Object>, Map<String, Object>> makeSupersetProjector(HashSet<Query> queries) {
    ArrayList<String> qs = new ArrayList<>(queries.size());
    for (Query query : queries) {
        qs.add(query.getRawQuery());
    }
    IFn ssProjector = (IFn) cljSuperset.invoke(new ArrayList(qs));
    return (datum) -> (Map<String, Object>) (ssProjector.invoke(datum));
}
Also used : IFn(io.mantisrx.mql.shaded.clojure.lang.IFn) Query(io.mantisrx.mql.jvm.core.Query) Clojure(io.mantisrx.mql.shaded.clojure.java.api.Clojure) HashSet(java.util.HashSet) Logger(org.slf4j.Logger) IFn(io.mantisrx.mql.shaded.clojure.lang.IFn) Map(java.util.Map) LoggerFactory(org.slf4j.LoggerFactory) Function(java.util.function.Function) ArrayList(java.util.ArrayList) Query(io.mantisrx.mql.jvm.core.Query) ArrayList(java.util.ArrayList) Map(java.util.Map)

Example 3 with Query

use of io.mantisrx.mql.jvm.core.Query in project mantis by Netflix.

the class AbstractAckableTaggingStage method tagData.

@SuppressWarnings("unchecked")
protected List<TaggedData> tagData(Map<String, Object> d, Context context) {
    List<TaggedData> taggedDataList = new ArrayList<>();
    boolean metaEvent = isMetaEvent(d);
    Metrics metrics = context.getMetricsRegistry().getMetric("mql");
    Collection<Query> queries = MQLQueryManager.getInstance().getRegisteredQueries();
    Iterator<Query> it = queries.iterator();
    while (it.hasNext()) {
        Query query = it.next();
        try {
            if (metaEvent) {
                TaggedData tg = new TaggedData(d);
                tg.addMatchedClient(query.getSubscriptionId());
                taggedDataList.add(tg);
            } else if (query.matches(d)) {
                Map<String, Object> projected = query.project(d);
                projected.put(MANTIS_META_SOURCE_NAME, d.get(MANTIS_META_SOURCE_NAME));
                projected.put(MANTIS_META_SOURCE_TIMESTAMP, d.get(MANTIS_META_SOURCE_TIMESTAMP));
                TaggedData tg = new TaggedData(projected);
                tg.addMatchedClient(query.getSubscriptionId());
                taggedDataList.add(tg);
            }
        } catch (Exception ex) {
            if (ex instanceof ClassNotFoundException) {
                logger.error("Error loading MQL: " + ex.getMessage());
                ex.printStackTrace();
                metrics.getCounter(MQL_CLASSLOADER_ERROR).increment();
            } else {
                ex.printStackTrace();
                metrics.getCounter(MQL_FAILURE).increment();
                logger.error("MQL Error: " + ex.getMessage());
                logger.error("MQL Query: " + query.getRawQuery());
                logger.error("MQL Datum: " + d);
            }
        } catch (Error e) {
            metrics.getCounter(MQL_FAILURE).increment();
            if (!errorLogged.get()) {
                logger.error("caught Error when processing MQL {} on {}", query.getRawQuery(), d.toString(), e);
                errorLogged.set(true);
            }
        }
    }
    return taggedDataList;
}
Also used : Metrics(io.mantisrx.common.metrics.Metrics) Query(io.mantisrx.mql.jvm.core.Query) ArrayList(java.util.ArrayList) TaggedData(io.mantisrx.sourcejob.kafka.core.TaggedData) HashMap(java.util.HashMap) Map(java.util.Map)

Example 4 with Query

use of io.mantisrx.mql.jvm.core.Query in project mantis by Netflix.

the class MQLQueryManager method registerQuery.

public void registerQuery(String id, String query) {
    query = MQL.transformLegacyQuery(query);
    Query q = MQL.makeQuery(id, query);
    queries.put(id, q);
}
Also used : Query(io.mantisrx.mql.jvm.core.Query)

Example 5 with Query

use of io.mantisrx.mql.jvm.core.Query in project mantis by Netflix.

the class TaggingStage method tagData.

private List<TaggedData> tagData(Map<String, Object> d, Context context) {
    List<TaggedData> taggedDataList = new ArrayList<>();
    Metrics metrics = context.getMetricsRegistry().getMetric(new MetricGroupId("mql"));
    Collection<Query> queries = MQLQueryManager.getInstance().getRegisteredQueries();
    Iterator<Query> it = queries.iterator();
    while (it.hasNext()) {
        Query query = it.next();
        try {
            if (query.matches(d)) {
                Map<String, Object> projected = query.project(d);
                projected.put(MANTIS_META_SOURCE_NAME, SYNTHETIC_REQUEST_SOURCE);
                projected.put(MANTIS_META_SOURCE_TIMESTAMP, System.currentTimeMillis());
                TaggedData tg = new TaggedData(projected);
                tg.addMatchedClient(query.getSubscriptionId());
                taggedDataList.add(tg);
            }
        } catch (Exception ex) {
            if (ex instanceof ClassNotFoundException) {
                log.error("Error loading MQL: " + ex.getMessage());
                ex.printStackTrace();
                metrics.getCounter(MQL_CLASSLOADER_ERROR).increment();
            } else {
                ex.printStackTrace();
                metrics.getCounter(MQL_FAILURE).increment();
                log.error("MQL Error: " + ex.getMessage());
                log.error("MQL Query: " + query.getRawQuery());
                log.error("MQL Datum: " + d);
            }
        } catch (Error e) {
            metrics.getCounter(MQL_FAILURE).increment();
            if (!errorLogged.get()) {
                log.error("caught Error when processing MQL {} on {}", query.getRawQuery(), d.toString(), e);
                errorLogged.set(true);
            }
        }
    }
    return taggedDataList;
}
Also used : Query(io.mantisrx.mql.jvm.core.Query) ArrayList(java.util.ArrayList) TaggedData(io.mantisrx.sourcejob.synthetic.core.TaggedData) Metrics(io.mantisrx.common.metrics.Metrics) MetricGroupId(io.mantisrx.common.metrics.spectator.MetricGroupId)

Aggregations

Query (io.mantisrx.mql.jvm.core.Query)6 Metrics (io.mantisrx.common.metrics.Metrics)3 ArrayList (java.util.ArrayList)3 Map (java.util.Map)3 Counter (io.mantisrx.common.metrics.Counter)1 MetricGroupId (io.mantisrx.common.metrics.spectator.MetricGroupId)1 Clojure (io.mantisrx.mql.shaded.clojure.java.api.Clojure)1 IFn (io.mantisrx.mql.shaded.clojure.lang.IFn)1 TaggedData (io.mantisrx.sourcejob.kafka.core.TaggedData)1 TaggedData (io.mantisrx.sourcejob.synthetic.core.TaggedData)1 ByteBuf (io.netty.buffer.ByteBuf)1 WriteBufferWaterMark (io.netty.channel.WriteBufferWaterMark)1 InetSocketAddress (java.net.InetSocketAddress)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 List (java.util.List)1 AtomicLong (java.util.concurrent.atomic.AtomicLong)1 Function (java.util.function.Function)1 HttpServerRequest (mantis.io.reactivex.netty.protocol.http.server.HttpServerRequest)1 HttpServerResponse (mantis.io.reactivex.netty.protocol.http.server.HttpServerResponse)1