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

com.tangosol.net.SimpleServiceMonitor Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2023, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * https://oss.oracle.com/licenses/upl.
 */
package com.tangosol.net;

import com.oracle.coherence.common.base.Blocking;

import com.tangosol.application.ContainerHelper;

import com.tangosol.internal.net.metrics.MetricsHttpHelper;
import com.tangosol.net.management.Registry;

import com.tangosol.util.Base;
import com.tangosol.util.CopyOnWriteMap;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;


/**
 * The {@link SimpleServiceMonitor} starts and monitors services that are
 * registered for monitoring.
 *
 * @author cf 2011.05.24
 * @author hr 2012.06.28
 * @author gh 2022.11.22
 * @since Coherence 12.1.2
 */
public class SimpleServiceMonitor
        implements ServiceMonitor
    {
    // ----- constructors ---------------------------------------------------

    /**
     * Construct a SimpleServiceMonitor with the default interval to check
     * that the registered services are running ({@link #DEFAULT_WAIT_MILLIS}).
     */
    public SimpleServiceMonitor()
        {
        this(DEFAULT_WAIT_MILLIS);
        }

    /**
     * Construct a SimpleServiceMonitor with the provided interval to check
     * that the registered services are running.
     *
     * @param cWaitMillis  the number of milliseconds in between checking
     *                     that the registered services are running
     */
    public SimpleServiceMonitor(long cWaitMillis)
        {
        m_cWaitMillis = cWaitMillis;
        }

    // ----- ServiceMonitor interface ---------------------------------------

    /**
     * {@inheritDoc}
     */
    @Override
    public void registerServices(Map mapServices)
        {
        Map mapServicesByName = m_mapServices;

        mapServicesByName.putAll(mapServices);

        if (!mapServicesByName.isEmpty())
            {
            start();
            }
        }

    /**
     * {@inheritDoc}
     */
    @Override
    public void unregisterServices(Set setServices)
        {
        Map mapServices = m_mapServices;

        mapServices.keySet().removeAll(setServices);

        if (mapServices.isEmpty())
            {
            stopMonitoring();
            }
        }

    /**
     * {@inheritDoc}
     */
    @Override
    public synchronized void stopMonitoring()
        {
        Thread thread = m_thread;

        if (thread != null)
            {
            thread.interrupt();
            try
                {
                thread.join(m_cWaitMillis);
                }
            catch (InterruptedException e)
                {
                // ignore since we are stopping
                }
            }

        m_fStarted = false;
        m_thread  = null;
        m_ccf     = null;
        }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isMonitoring()
        {
        return m_fStarted;
        }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setConfigurableCacheFactory(ConfigurableCacheFactory ccf)
        {
        m_ccf = ccf;
        }

    /**
     * {@inheritDoc}
     */
    @Override
    public Thread getThread()
        {
        return m_thread;
        }


    // ----- Disposable interface -------------------------------------------

    /**
     * {@inheritDoc}
     */
    @Override
    public void dispose()
        {
        m_fDisposed = true;
        m_ccf       = null;

        stopMonitoring();
        }

    // ----- helpers --------------------------------------------------------

    /**
     * Start monitoring the services.
     */
    protected synchronized void start()
        {
        if (!m_fStarted)
            {
            assertNotDisposed();

            Thread thread = m_thread = Base.makeThread(THREAD_GROUP, new Runnable()
                {
                public void run()
                    {
                    monitorServices(m_cWaitMillis);
                    }
                }, "ServiceMonitor");
            thread.setDaemon(true);
            thread.start();

            m_fStarted = true;
            }
        }

    /**
     * Check the service status periodically (keep alive interval), restarting
     * any stopped services.
     *
     * @param cWaitMillis  the number of milliseconds between checks
     */
    protected void monitorServices(long cWaitMillis)
        {
        Thread   thread    = m_thread;
        Cluster  cluster   = CacheFactory.getCluster();
        Registry registry  = cluster == null || !cluster.isRunning() ? null : cluster.getManagement();
        String   sNodeName = registry == null
                ? null : registry.ensureGlobalName(Registry.NODE_TYPE);

        Base.azzert(thread == Thread.currentThread(),
                "monitorServices should only be called on the ServiceMonitor thread");
        while (!thread.isInterrupted())
            {
            try
                {
                Blocking.sleep(cWaitMillis);

                ConfigurableCacheFactory ccf = m_ccf;
                for (Map.Entry entry : m_mapServices.entrySet())
                    {
                    Service service = entry.getKey();
                    if (!service.isRunning())
                        {
                        ContainerHelper.initializeThreadContext(service);

                        if (ccf == null)
                            {
                            service.start();
                            }
                        else
                            {
                            // the reference to the safe service continues to
                            // exist and be valid

                            String sServiceName = entry.getValue();
                            if (MetricsHttpHelper.getServiceName().equals(sServiceName))
                                {
                                MetricsHttpHelper.ensureMetricsService(m_mapServices);
                                }
                            else
                                {
                                // Ensure the Scheme-based Service
                                ccf.ensureService(sServiceName);
                                }
                            }
                        }
                    }

                // Note: this Registry.isRegistered call is a 'heartbeat' against
                //       the management service to ensure it is running
                if (registry != null && !registry.isRegistered(sNodeName))
                    {
                    // the node name may change due to cluster restart
                    sNodeName = registry.ensureGlobalName(Registry.NODE_TYPE);
                    }
                }
            catch (RuntimeException e)
                {
                CacheFactory.log("Failed to restart services: " + e.getMessage()
                    + "\n" + Base.getStackTrace(e), CacheFactory.LOG_ERR);
                }
            catch (InterruptedException e)
                {
                break;
                }
            }
        }

    /**
     * Return true if this {@link ServiceMonitor} has been disposed via
     * invocation of {@link #dispose()}.
     *
     * @return true if this monitor has been disposed
     */
    protected boolean isDisposed()
        {
        return m_fDisposed;
        }

    /**
     * Throws {@link IllegalStateException} if this monitor has been disposed
     * via invocation of {@link #dispose()}.
     *
     * @throws IllegalStateException if this monitor has been disposed
     */
    protected void assertNotDisposed()
        {
        if (isDisposed())
            {
            throw new IllegalStateException("This ServiceMonitor has been disposed and cannot be reused");
            }
        }

    // ----- data fields and constants --------------------------------------

    /**
     * The default time interval by which we check the alive status.
     */
    protected static final Integer DEFAULT_WAIT_MILLIS = 5000;

    /**
     * The {@link ThreadGroup} used to group service monitor threads.
     */
    private   static final ThreadGroup THREAD_GROUP = new ThreadGroup("ServiceMonitors");

    /**
     * Indicates that the {@link ServiceMonitor} has started.
     */
    protected volatile boolean m_fStarted;

    /**
     * The {@link Thread} we are using for monitoring the services periodically.
     */
    protected Thread m_thread;

    /**
     * Indicates that this {@link ServiceMonitor} has been disposed.
     */
    protected boolean m_fDisposed;

    /**
     * A {@link ConfigurableCacheFactory} instance used to start the service.
     */
    // Note: m_ccf is not volatile as by the contract a stop and start of
    //       the monitor is required for CCF changes to be reflected.
    protected ConfigurableCacheFactory m_ccf;

    /**
     * A map of {@link Service}s to be monitored with values being non-scoped service names.
     */
    protected Map m_mapServices = new CopyOnWriteMap(HashMap.class);

    /**
     * The number of milliseconds between checking the status of the services.
     */
    protected final long m_cWaitMillis;
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy