public void start() {
        this.running = true;
        var metricsConsumerThread = new Thread(() -> {
            LOGGER.info("Starting metrics consumer: {0}...", metricConsumerName);
            while (running) {
                while (metricQueue.isEmpty()) {
                    Thread.onSpinWait();
                }
                try {
                    consumeBatch();
                } catch (RuntimeException rte) {
                    LOGGER.error("An error occurred when consuming a batch of metrics; this will be ignored so that the metrics subsystem can continue functioning. "
                                         + "Implementors should handle any errors in their code to prevent entire batches being dropped.", rte);
                    LOGGER.warn("Dropping {0} metrics", batchBuffer.size());
                }
                // Must always clear batch buffer, even if exception occurs.
                batchBuffer.clear();
            }
        }, metricConsumerName);
        metricsConsumerThread.setDaemon(true);
        metricsConsumerThread.start();
    }
Batched metrics consumer. Uses a single spin-wait daemon thread to poll a {@link ManyToOneConcurrentArrayQueue}. Calls to {@link #offer(Object)} are thread safe.
<p>
This implementation will flush to the batchHandler as fast as it can, with a maximum batch size specified.
<p>
It is generally acceptable for implementors to use the metric processing thread to perform whatever actions are required to dispatch their metrics; new metrics will
be queued up until the thread becomes available again, as long as this is not an excessively long period of time (i.e. allowing the buffer to overflow).
<p>
Important: The List<M> provided to batchHandler is cleared after the callback returns, so don't hold onto it.

@author Marc Savy {@literal <marc@blackparrotlabs.io>}
gateway/engine/core/src/main/java/io/apiman/gateway/engine/metrics/BatchedMetricsConsumer.java