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

eventstore.cluster.ClusterSettings.scala Maven / Gradle / Ivy

The newest version!
package eventstore
package cluster

import java.net.InetSocketAddress
import com.typesafe.config.Config
import eventstore.util.ToCoarsest
import scala.collection.JavaConverters._
import scala.concurrent.duration._

/**
 * Contains settings relating to a connection to a cluster.
 *
 * @param gossipSeedsOrDns Gossip seeds or DNS settings
 * @param dnsLookupTimeout The time given to resolve dns
 * @param maxDiscoverAttempts Maximum number of attempts for discovering endpoints
 * @param discoverAttemptInterval The interval between cluster discovery attempts
 * @param discoveryInterval The interval at which to keep discovering cluster
 * @param gossipTimeout Timeout for cluster gossip.
 */
case class ClusterSettings(
    gossipSeedsOrDns: GossipSeedsOrDns = GossipSeedsOrDns.GossipSeeds("127.0.0.1" :: 2113),
    dnsLookupTimeout: FiniteDuration = 2.seconds,
    maxDiscoverAttempts: Int = 10,
    discoverAttemptInterval: FiniteDuration = 500.millis,
    discoveryInterval: FiniteDuration = 1.second,
    gossipTimeout: FiniteDuration = 1.second) {
  require(maxDiscoverAttempts >= 1, s"maxDiscoverAttempts must be >= 1, but is $maxDiscoverAttempts")
}

object ClusterSettings {
  def opt(conf: Config): Option[ClusterSettings] = {
    def opt(conf: Config) = {
      def option[T](path: String, f: String => T): Option[T] = {
        if (conf hasPath path) Option(f(path)) else None
      }

      def clusterDns = option("dns", conf.getString).map { dns =>
        GossipSeedsOrDns(
          clusterDns = dns,
          externalGossipPort = conf getInt "external-gossip-port")
      }

      def gossipSeeds = option("gossip-seeds", conf.getStringList).flatMap { ss =>
        if (ss.isEmpty) None
        else {
          val seeds = ss.asScala.map { s =>
            s.split(":") match {
              case Array(host, port) => new InetSocketAddress(host, port.toInt)
              case _                 => sys.error(s"Cannot parse address from $s, expected format is host:port")
            }
          }
          Some(GossipSeedsOrDns.GossipSeeds(seeds.toList))
        }
      }

      def duration(path: String) = ToCoarsest(FiniteDuration(conf.getDuration(path, MILLISECONDS), MILLISECONDS))

      (clusterDns orElse gossipSeeds).map { gossipSeedsOrDns =>
        ClusterSettings(
          gossipSeedsOrDns = gossipSeedsOrDns,
          dnsLookupTimeout = duration("dns-lookup-timeout"),
          maxDiscoverAttempts = conf getInt "max-discover-attempts",
          discoverAttemptInterval = duration("discover-attempt-interval"),
          discoveryInterval = duration("discovery-interval"),
          gossipTimeout = duration("gossip-timeout"))
      }
    }
    opt(conf getConfig "eventstore.cluster")
  }
}

sealed trait GossipSeedsOrDns

object GossipSeedsOrDns {
  def apply(clusterDns: String): GossipSeedsOrDns = ClusterDns(clusterDns)

  def apply(clusterDns: String, externalGossipPort: Int): GossipSeedsOrDns = ClusterDns(clusterDns, externalGossipPort)

  def apply(gossipSeeds: InetSocketAddress*): GossipSeedsOrDns = GossipSeeds(gossipSeeds.toList)

  /**
   * Used if we're discovering via DNS
   *
   * @param clusterDns The DNS name to use for discovering endpoints.
   * @param externalGossipPort The well-known endpoint on which cluster managers are running.
   */
  case class ClusterDns(
      clusterDns: String = "localhost",
      externalGossipPort: Int = 30778) extends GossipSeedsOrDns {
    require(0 < externalGossipPort && externalGossipPort < 65536, s"externalGossipPort is not valid :$externalGossipPort")
    require(clusterDns != null, "clusterDns must be not null")
    require(clusterDns.nonEmpty, "clusterDns must be not empty")
  }

  /**
   * Used if we're connecting with gossip seeds
   *
   * @param gossipSeeds Endpoints for seeding gossip.
   */
  case class GossipSeeds(gossipSeeds: List[InetSocketAddress]) extends GossipSeedsOrDns {
    require(gossipSeeds.nonEmpty, s"gossipSeeds must be non empty")
  }

  object GossipSeeds {
    def apply(gossipSeeds: InetSocketAddress*): GossipSeeds = GossipSeeds(gossipSeeds.toList)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy