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

com.ajjpj.asysmon.datasink.offloadhttpjson.AHttpJsonOffloadingDataSink Maven / Gradle / Ivy

There is a newer version: 1.0-pre28
Show newest version
package com.ajjpj.asysmon.datasink.offloadhttpjson;

import com.ajjpj.abase.collection.mutable.ASoftlyLimitedQueue;
import com.ajjpj.asysmon.ASysMonApi;
import com.ajjpj.asysmon.config.ASysMonConfig;
import com.ajjpj.asysmon.config.log.ASysMonLogger;
import com.ajjpj.asysmon.data.AHierarchicalDataRoot;
import com.ajjpj.asysmon.data.AScalarDataPoint;
import com.ajjpj.asysmon.datasink.ADataSink;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/**
 * @author arno
 */
public class AHttpJsonOffloadingDataSink implements ADataSink {
    public static final int NO_DATA_SLEEP_MILLIS = 10;

    private static final ASysMonLogger log = ASysMonLogger.get(AHttpJsonOffloadingDataSink.class);

    private final ASysMonConfig config;

    //TODO how many concurrent HTTP connections does this provide? --> configure!
    private final CloseableHttpClient httpClient = HttpClients.createDefault(); //TODO make this configurable
    private final URI uri;

    private final String sender;
    private final String senderInstance;

    private final ASoftlyLimitedQueue traceQueue;
    private final ASoftlyLimitedQueue scalarQueue;

    private final ExecutorService offloadingThreadPool;
    private final ScheduledExecutorService scalarMeasurementPool;

    private volatile boolean isShutDown = false;

    public AHttpJsonOffloadingDataSink(final ASysMonApi sysMon, String uri, String sender, String senderInstance, int traceQueueSize, int scalarQueueSize, int numOffloadingThreads, int scalarMeasurementFrequencyMillis) {
        this.config = sysMon.getConfig();

        this.uri = URI.create(uri);
        this.sender = sender;
        this.senderInstance = senderInstance;

        this.traceQueue = new ASoftlyLimitedQueue(traceQueueSize, new DiscardedLogger("trace queue overflow - discarding oldest trace"));
        this.scalarQueue = new ASoftlyLimitedQueue(scalarQueueSize, new DiscardedLogger("environment queue overflow - discarding oldest data"));

        offloadingThreadPool = Executors.newFixedThreadPool(numOffloadingThreads);
        for(int i=0; i send a unique identifier with every *atom* (trace, environment measurement, ...)
        //TODO re-enter the data into the queues when the server returns a non-OK http response code

        traceQueue.add(data);
    }

    private void doOffload() throws Exception {
        final List traces = new ArrayList();
        AHierarchicalDataRoot candidate;
        while ((candidate = traceQueue.poll()) != null) { //TODO limit number per HTTP request?!
            traces.add(candidate);
        }

        final List scalars = new ArrayList();
        AScalarDataPoint scalar;
        while ((scalar = scalarQueue.poll()) != null) { //TODO limit number per HTTP request?
            scalars.add(scalar);
        }

        if(traces.isEmpty() && scalars.isEmpty()) {
            Thread.sleep(NO_DATA_SLEEP_MILLIS);
        }
        else {
            try {
            final HttpPost httpPost = new HttpPost(uri);

                final AJsonOffloadingEntity entity = new AJsonOffloadingEntity(traces, scalars, sender, senderInstance);
                httpPost.setEntity(entity);

                final CloseableHttpResponse response = httpClient.execute(httpPost);
                try {
                    //TODO response with commands for monitoring this app?!
                } finally {
                    response.close();
                }
            }
            catch(Exception exc) {
                log.error(exc);

                // add the data to the queue again for later retry
                scalarQueue.addAll(scalars);

                System.out.println(" == " + scalarQueue);

                // wait a grace period for the situation to improve
                Thread.sleep(5000); //TODO make this configurable
            }
        }
    }

    @Override public void shutdown() throws IOException {
        isShutDown = true;
        httpClient.close();
        scalarMeasurementPool.shutdown();
        offloadingThreadPool.shutdown();
    }

    private static class DiscardedLogger implements Runnable {
        private final String msg;

        private DiscardedLogger(String msg) {
            this.msg = msg;
        }

        @Override public void run() {
            log.warn(msg);
        }
    }

    private class OffloadingRunnable implements Runnable {
        @Override public void run() {
            while(! isShutDown) {
                try {
                    doOffload();
                } catch (Exception e) {
                    e.printStackTrace(); //TODO exception handling
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy