@@ -36,8 +36,7 @@ internal class RedisHighAvailabilityContextCustomizer(
3636 private val manuallySpecifiedPorts =
3737 config.ports.filter { it != 0 }.toSet() + config.sentinels.map { it.port }.filter { it != 0 }.toSet()
3838 private val name = config.name.ifEmpty { BirdNameProvider .next() }.replace(Regex (" [^a-zA-Z0-9]" ), " " )
39- private lateinit var nodePorts: Iterator <Int >
40- private lateinit var nodeBinds: Iterator <String >
39+ private lateinit var nodeProvider: NodeProvider
4140 private val customizer = config.customizer.map { c -> c.createInstance() }.toList()
4241
4342 override fun customizeContext (context : ConfigurableApplicationContext , mergedConfig : MergedContextConfiguration ) {
@@ -52,8 +51,7 @@ internal class RedisHighAvailabilityContextCustomizer(
5251 }
5352
5453 private fun createAndStartRedisInHighAvailabilityMode (context : ConfigurableApplicationContext ): RedisCluster {
55- nodePorts = ports().iterator()
56- nodeBinds = binds().iterator()
54+ nodeProvider = nodeProvider()
5755 val redisHighAvailability = createRedisInHighAvailabilityMode(context)
5856 redisHighAvailability.start()
5957 log.info(" Started Redis in high availability mode on ports ${redisHighAvailability.ports()} " )
@@ -63,24 +61,25 @@ internal class RedisHighAvailabilityContextCustomizer(
6361 private fun createRedisInHighAvailabilityMode (context : ConfigurableApplicationContext ): RedisCluster {
6462 val replicationGroup = createReplicationGroup(context)
6563 val sentinels = config.sentinels.map { createSentinel(it, replicationGroup) }
66- return RedisCluster (sentinels, replicationGroup.second + replicationGroup.first.node )
64+ return RedisCluster (sentinels, replicationGroup.second)
6765 }
6866
6967 private fun createReplicationGroup (context : ConfigurableApplicationContext ): Pair <Node , List <RedisServer >> {
7068 val mainNode = createAndStartMainNode(context)
7169 val replicaBuilders =
7270 IntStream .range(0 , config.replicas)
73- .mapToObj { _ -> createReplicaBuilder(mainNode) }
71+ .mapToObj { _ -> createReplicaBuilder(mainNode.first ) }
7472 .toList()
7573 customizer.forEach { c -> c.customizeReplicas(replicaBuilders, config) }
7674
77- return Pair (mainNode, replicaBuilders.map { it.build() })
75+ return Pair (mainNode.first , replicaBuilders.map { it.build() } + mainNode.second )
7876 }
7977
80- private fun createAndStartMainNode (context : ConfigurableApplicationContext ): Node {
78+ private fun createAndStartMainNode (context : ConfigurableApplicationContext ): Pair <Node , RedisServer > {
79+ val nextNode = nodeProvider.next()
8180 val builder = RedisServer .newRedisServer()
82- .bind(nodeBinds.next() )
83- .port(nodePorts.next() )
81+ .bind(nextNode.bind )
82+ .port(nextNode.port )
8483 if (config.executeInDirectory.isNotEmpty()) {
8584 builder.executableProvider(ExecutableProvider .newJarResourceProvider(File (config.executeInDirectory)))
8685 }
@@ -95,29 +94,37 @@ internal class RedisHighAvailabilityContextCustomizer(
9594 stopSafely(mainNode)
9695 }
9796 }
98- return Node (mainNode)
97+ return Node (mainNode) to mainNode
9998 }
10099
101100 private fun createReplicaBuilder (
102101 mainNode : Node
103102 ): RedisServerBuilder {
103+ val nextNode = nodeProvider.next()
104104 val builder = RedisServer .newRedisServer()
105- .bind(nodeBinds.next() )
106- .port(nodePorts.next() )
105+ .bind(nextNode.bind )
106+ .port(nextNode.port )
107107 .slaveOf(mainNode.bind, mainNode.port)
108108 if (config.executeInDirectory.isNotEmpty()) {
109109 builder.executableProvider(ExecutableProvider .newJarResourceProvider(File (config.executeInDirectory)))
110110 }
111111 return builder
112112 }
113113
114- private fun ports (): List < Int > {
115- return if (config.ports.isEmpty()) {
114+ private fun nodeProvider (): NodeProvider {
115+ val ports = if (config.ports.isEmpty()) {
116116 val nOfNodes = config.replicas + 1
117117 IntStream .range(0 , nOfNodes).map { _ -> unspecifiedUnusedPort() }.toList()
118118 } else {
119119 config.ports.map { if (it == 0 ) unspecifiedUnusedPort() else it }.toList()
120120 }
121+ val binds = if (config.binds.isEmpty()) {
122+ val nOfNodes = config.replicas + 1
123+ IntStream .range(0 , nOfNodes).mapToObj { _ -> DEFAULT_BIND }.toList()
124+ } else {
125+ config.binds.map { it.ifEmpty { DEFAULT_BIND } }.toList()
126+ }
127+ return NodeProvider (ports, binds)
121128 }
122129
123130 private fun unspecifiedUnusedPort (sentinel : Boolean = false): Int {
@@ -128,15 +135,6 @@ internal class RedisHighAvailabilityContextCustomizer(
128135 return port
129136 }
130137
131- private fun binds (): List <String > {
132- return if (config.binds.isEmpty()) {
133- val nOfNodes = config.replicas + 1
134- IntStream .range(0 , nOfNodes).mapToObj { _ -> DEFAULT_BIND }.toList()
135- } else {
136- config.binds.map { it.ifEmpty { DEFAULT_BIND } }.toList()
137- }
138- }
139-
140138 private fun createSentinel (
141139 sentinelConfig : EmbeddedRedisHighAvailability .Sentinel ,
142140 replicationGroup : Pair <Node , List <RedisServer >>
@@ -213,9 +211,18 @@ internal class RedisHighAvailabilityContextCustomizer(
213211 return config.hashCode()
214212 }
215213
216- internal data class Node (val node : RedisServer , val port : Int , val bind : String ) {
214+ internal class NodeProvider (private val addresses : Iterator <Pair <Int , String >>) {
215+
216+ constructor (ports: List <Int >, binds: List <String >) : this (ports.zip(binds).iterator())
217+
218+ fun next (): Node {
219+ val (port, bind) = addresses.next()
220+ return Node (port, bind)
221+ }
222+ }
223+
224+ internal data class Node (val port : Int , val bind : String ) {
217225 constructor (node: RedisServer ) : this (
218- node,
219226 node.ports().first(),
220227 parseBindAddress(node)
221228 )
0 commit comments