Package org.springframework.xd.dirt.server

Source Code of org.springframework.xd.dirt.server.ContainerListener$ArrivingContainerDeployer

/*
* Copyright 2014 the original author or authors.
*
* 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 org.springframework.xd.dirt.server;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.xd.dirt.cluster.Container;
import org.springframework.xd.dirt.cluster.ContainerMatcher;
import org.springframework.xd.dirt.container.store.ContainerRepository;
import org.springframework.xd.dirt.core.Job;
import org.springframework.xd.dirt.core.Stream;
import org.springframework.xd.dirt.job.JobFactory;
import org.springframework.xd.dirt.stream.StreamFactory;
import org.springframework.xd.dirt.zookeeper.Paths;
import org.springframework.xd.dirt.zookeeper.ZooKeeperConnection;
import org.springframework.xd.dirt.zookeeper.ZooKeeperUtils;

/**
* Listener implementation that is invoked when containers are added/removed/modified.
*
* @author Patrick Peralta
* @author Mark Fisher
* @author Ilayaperumal Gopinathan
*/
public class ContainerListener implements PathChildrenCacheListener {

  /**
   * Logger.
   */
  private final Logger logger = LoggerFactory.getLogger(ContainerListener.class);

  /**
   * The {@link ModuleRedeployer} that deploys unallocated stream/job modules
   * upon new container arrival.
   */
  private final ModuleRedeployer arrivingContainerModuleRedeployer;

  /**
   * The {@link ModuleRedeployer} that re-deploys the stream/job modules
   * that were deployed at the departing container.
   */
  private final ModuleRedeployer departingContainerModuleRedeployer;

  /**
   * Runnable that deploys modules to new containers.
   */
  private final ArrivingContainerDeployer arrivingContainerDeployer = new ArrivingContainerDeployer();

  /**
   * The amount of time that must elapse after the newest container arrives
   * before deployments to new containers are initiated.
   */
  private final AtomicLong quietPeriod;

  /**
   * Executor service for module deployments
   */
  private final ScheduledExecutorService executorService;

  /**
   * Container and timestamp info for newest container.
   */
  private final AtomicReference<ContainerArrival> latestContainer = new AtomicReference<ContainerArrival>();

  /**
   * Construct a ContainerListener.
   *
   * @param zkConnection ZooKeeper connection
   * @param streamFactory factory to construct {@link Stream}
   * @param jobFactory factory to construct {@link Job}
   * @param streamDeployments cache of children for stream deployments path
   * @param jobDeployments cache of children for job deployments path
   * @param moduleDeploymentRequests cache of children for requested module deployments path
   * @param containerMatcher matches modules to containers
   * @param stateCalculator calculator for stream/job state
   * @param quietPeriod AtomicLong indicating quiet period for new container module deployments
   */
  public ContainerListener(ZooKeeperConnection zkConnection,
      ContainerRepository containerRepository,
      StreamFactory streamFactory, JobFactory jobFactory,
      PathChildrenCache streamDeployments, PathChildrenCache jobDeployments,
      PathChildrenCache moduleDeploymentRequests, ContainerMatcher containerMatcher,
      DeploymentUnitStateCalculator stateCalculator,
      ScheduledExecutorService executorService, AtomicLong quietPeriod) {
    this.arrivingContainerModuleRedeployer = new ArrivingContainerModuleRedeployer(zkConnection,
        containerRepository, streamFactory, jobFactory, streamDeployments, jobDeployments,
        moduleDeploymentRequests, containerMatcher, stateCalculator);
    this.departingContainerModuleRedeployer = new DepartingContainerModuleRedeployer(zkConnection,
        containerRepository, streamFactory, jobFactory, moduleDeploymentRequests, containerMatcher,
        stateCalculator);
    this.quietPeriod = quietPeriod;
    this.executorService = executorService;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
    ZooKeeperUtils.logCacheEvent(logger, event);
    Container container;
    switch (event.getType()) {
      case CHILD_ADDED:
        container = getContainer(event.getData());
        logger.info("Container arrived: {}", container);
        latestContainer.set(new ContainerArrival(container, System.currentTimeMillis()));
        arrivingContainerDeployer.schedule();
        break;
      case CHILD_UPDATED:
        break;
      case CHILD_REMOVED:
        container = getContainer(event.getData());
        logger.info("Container departed: {}", container);
        this.departingContainerModuleRedeployer.deployModules(container);
        break;
      case CONNECTION_SUSPENDED:
        break;
      case CONNECTION_RECONNECTED:
        break;
      case CONNECTION_LOST:
        break;
      case INITIALIZED:
        break;
    }
  }

  /**
   * Get the {@link Container} from the data.
   *
   * @param data the ChildData that the ContainerListener event receives.
   * @return the container that represents name and attributes.
   */
  private Container getContainer(ChildData data) {
    return new Container(Paths.stripPath(data.getPath()), ZooKeeperUtils.bytesToMap(data.getData()));
  }


  /**
   * Holder to keep track of the latest arrived container and
   * the time it arrived.
   */
  private class ContainerArrival {
    final Container container;
    final long timestamp;

    private ContainerArrival(Container container, long timestamp) {
      this.container = container;
      this.timestamp = timestamp;
    }
  }


  /**
   * Runnable that performs new container module deployments. It schedules
   * itself for execution on {@link #executorService} based on the last
   * container arrival time and the configured {@link #quietPeriod}.
   *
   * To request new container module deployments, invoke {@link #schedule}.
   */
  private class ArrivingContainerDeployer implements Runnable {

    /**
     * Flag to indicate whether this deployer has already been
     * scheduled for execution on {@link #executorService}.
     */
    private final AtomicBoolean scheduled = new AtomicBoolean(false);

    /**
     * Schedule new container module deployments. This is scheduled
     * for execution {@link #quietPeriod} milliseconds after the
     * latest container arrival. If this runnable has already been
     * scheduled, invoking this method has no effect.
     */
    void schedule() {
      if (scheduled.compareAndSet(false, true)) {
        long delay = Math.max(0, quietPeriod.get() -
            (System.currentTimeMillis() - latestContainer.get().timestamp));
        logger.info("Scheduling deployments to new container(s) in {} ms ", delay);
        executorService.schedule(arrivingContainerDeployer, delay, TimeUnit.MILLISECONDS);
      }
      else {
        logger.trace("Container deployment already scheduled");
      }
    }

    /**
     * If {@link #quietPeriod} milliseconds have passed since the
     * newest container arrived (see {@link #latestContainer}),
     * deploy new modules using {@link #arrivingContainerDeployer}.
     * If the quiet period has not elapsed, reschedule execution
     * of this runnable.
     */
    @Override
    public void run() {
      scheduled.set(false);
      ContainerArrival containerArrival = latestContainer.get();
      if (containerArrival != null) {
        if (System.currentTimeMillis() >= containerArrival.timestamp + quietPeriod.get()) {
          try {
            arrivingContainerModuleRedeployer.deployModules(containerArrival.container);
            latestContainer.compareAndSet(containerArrival, null);
          }
          catch (Exception e) {
            logger.error("Error deploying to container " + containerArrival.container, e);
          }
        }
        else {
          logger.trace("Quiet period not over yet; rescheduling container deployment");
          schedule();
        }
      }
      else {
        logger.trace("Arrived container already processed");
      }
    }
  }

}
TOP

Related Classes of org.springframework.xd.dirt.server.ContainerListener$ArrivingContainerDeployer

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.