Package com.betfair.cougar.transport.nio

Source Code of com.betfair.cougar.transport.nio.ApplicationHealthMonitor

/*
* Copyright 2013, The Sporting Exchange Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.betfair.cougar.transport.nio;

import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import com.betfair.tornjak.monitor.MonitorRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.betfair.cougar.api.Service;
import com.betfair.cougar.core.api.ServiceAware;
import com.betfair.cougar.transport.nio.HealthMonitorStrategy.HealthMonitorStrategyListener;
import com.betfair.tornjak.monitor.Status;
import com.betfair.tornjak.monitor.StatusAggregator;
import com.betfair.tornjak.monitor.StatusChangeEvent;
import com.betfair.tornjak.monitor.StatusChangeListener;

/**
* Actively monitors the state of the host application to inform interested parties (via a configurable strategy) of the host's health
* Can be configured to either actively or passively monitor the application health.  If passive then subscribes to updates from StatusAggregators, this assumes
* an external party (such as netscalers) are causing status updates.  If active monitoring then a thread is started to periodically poll application health.
* </p>
* If any service hosted in the container is unhealthy, then the result is 'unhealthy'
* </p>
* Only status 'FAIL' is considered unhealthy (WARN is not)
* </p>
* passive monitoring only receives updates when the status changes, so it's important a suitable strategy is used.  DebounceHealthMonitorStrategy suites
* passive monitoring, CountingHealthMonitorStrategy suites active monitoring.
*/
public class ApplicationHealthMonitor  implements ServiceAware {
 
  private static final Logger log = LoggerFactory.getLogger(ApplicationHealthMonitor.class);        

  private final long           monitorInterval;
  private final HealthMonitorStrategy strategy;
    private final MonitorRegistry monitorRegistry;


    public ApplicationHealthMonitor(final ExecutionVenueNioServer nioServer,
                                    HealthMonitorStrategy strategy,
                                    long monitorInterval,
                                    MonitorRegistry monitorRegistry) {
        this.monitorInterval = monitorInterval;
        this.strategy = strategy;
        this.strategy.registerListener(new HealthMonitorStrategyListener() {
     
      @Override
      public void onUpdate(boolean isHealthy) {
        if (log.isDebugEnabled()) {
          log.debug("updating health state to " + isHealthy);
        }
        nioServer.setHealthState(isHealthy);
       
      }
    });
        this.monitorRegistry = monitorRegistry;

        log.info("socket health monitor using strategy " + strategy.getClass().getName());
    }
   
  @Override
  public void setServices(Set<Service> services) {
    if (monitorInterval > 0) {
      startActiveMonitoring(monitorRegistry.getStatusAggregator());
    }
    else {
      startPassiveMonitoring(monitorRegistry.getStatusAggregator());
    }
   
  }
   

  /**
   * Add listeners to all status aggregators to be advised when status of the aggregator changes
   * </p>
   * Keep track of all current status.  if, after update, all status are healthy then overall status = healthy, otherwise = unhealthy.
   * </p>
   * advise strategy only if the overall status has changed
   */
    private void startPassiveMonitoring(final StatusAggregator aggregator) {
     
      log.info("Starting application health monitoring in PASSIVE mode");

        final AtomicBoolean health = new AtomicBoolean();
        health.set(!Status.FAIL.equals(aggregator.getStatus()));

        aggregator.addStatusChangeListener(new StatusChangeListener() {

            @Override
            public void statusChanged(StatusChangeEvent event) {
                boolean healthStatusChanged ;
                boolean isHealthy;
                synchronized (health) {
                    boolean currentOverallHealth = health.get()//true iff all services are healthy
                    isHealthy = !Status.FAIL.equals(event.getNewStatus());         //service is healthy if not fail status
                    health.set(isHealthy);
                    healthStatusChanged = currentOverallHealth != isHealthy;
                }
                if (healthStatusChanged) {
                    strategy.update(isHealthy);
                }
            }
        });
    strategy.update(health.get());
  }

    /**
     * Start a new thread and periodically poll all status aggregators for their current status
     * </p>
     * Calculate a new status where newStatus = healthy if all aggregator's status = healthy
     */
  private void startActiveMonitoring(final StatusAggregator aggregator) {
   
      log.info("Starting application health monitoring in ACTIVE mode");
     
      ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
     
      @Override
      public Thread newThread(Runnable r) {
        Thread t = new Thread(r,"SocketTransport App Health Monitor");
        t.setDaemon(true);
        return t;
      }
    });
     
      executor.scheduleWithFixedDelay(new Runnable() {
     
      @Override
      public void run() {
                try {
                    boolean healthy = !Status.FAIL.equals(aggregator.getStatus());

                    setStatus(healthy ? Status.OK : Status.FAIL);
                }
                catch (Exception e) {
                    log.warn("Error whilst setting health status",e);
                }
      }
    }, monitorInterval, monitorInterval, TimeUnit.MILLISECONDS);
    }


    private void setStatus(Status status) {
        boolean isUnhealthy = Status.FAIL.equals(status);
        strategy.update(!isUnhealthy);
    }

}
TOP

Related Classes of com.betfair.cougar.transport.nio.ApplicationHealthMonitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.