mirror of
https://github.com/corda/corda.git
synced 2025-01-18 18:56:28 +00:00
NOTICK - fix network builder for v4 (#5205)
make builder more parallel by making docker node building async
This commit is contained in:
parent
5713865702
commit
6c05197954
@ -5,8 +5,10 @@ import net.corda.bootstrapper.context.Context
|
|||||||
import net.corda.bootstrapper.nodes.*
|
import net.corda.bootstrapper.nodes.*
|
||||||
import net.corda.bootstrapper.notaries.NotaryCopier
|
import net.corda.bootstrapper.notaries.NotaryCopier
|
||||||
import net.corda.bootstrapper.notaries.NotaryFinder
|
import net.corda.bootstrapper.notaries.NotaryFinder
|
||||||
|
import net.corda.node.utilities.NamedThreadFactory
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
interface NetworkBuilder {
|
interface NetworkBuilder {
|
||||||
|
|
||||||
@ -31,12 +33,10 @@ interface NetworkBuilder {
|
|||||||
fun onNodeStartBuild(callback: (FoundNode) -> Unit): NetworkBuilder
|
fun onNodeStartBuild(callback: (FoundNode) -> Unit): NetworkBuilder
|
||||||
fun onNodePushStart(callback: (BuiltNode) -> Unit): NetworkBuilder
|
fun onNodePushStart(callback: (BuiltNode) -> Unit): NetworkBuilder
|
||||||
fun onNodeInstancesRequested(callback: (List<NodeInstanceRequest>) -> Unit): NetworkBuilder
|
fun onNodeInstancesRequested(callback: (List<NodeInstanceRequest>) -> Unit): NetworkBuilder
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NetworkBuilderImpl : NetworkBuilder {
|
private class NetworkBuilderImpl : NetworkBuilder {
|
||||||
|
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
private var onNodeLocatedCallback: ((FoundNode) -> Unit) = {}
|
private var onNodeLocatedCallback: ((FoundNode) -> Unit) = {}
|
||||||
@Volatile
|
@Volatile
|
||||||
@ -76,7 +76,6 @@ private class NetworkBuilderImpl : NetworkBuilder {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onNodeStartBuild(callback: (FoundNode) -> Unit): NetworkBuilder {
|
override fun onNodeStartBuild(callback: (FoundNode) -> Unit): NetworkBuilder {
|
||||||
this.onNodeBuildStartCallback = callback
|
this.onNodeBuildStartCallback = callback
|
||||||
return this;
|
return this;
|
||||||
@ -127,8 +126,10 @@ private class NetworkBuilderImpl : NetworkBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun build(): CompletableFuture<Pair<List<NodeInstance>, Context>> {
|
override fun build(): CompletableFuture<Pair<List<NodeInstance>, Context>> {
|
||||||
|
|
||||||
|
val executor = Executors.newCachedThreadPool(NamedThreadFactory("network-builder"))
|
||||||
|
|
||||||
val cacheDir = File(workingDir, cacheDirName)
|
val cacheDir = File(workingDir, cacheDirName)
|
||||||
val baseDir = workingDir!!
|
val baseDir = workingDir!!
|
||||||
val context = Context(networkName, backendType, backendOptions)
|
val context = Context(networkName, backendType, backendOptions)
|
||||||
@ -163,12 +164,21 @@ private class NetworkBuilderImpl : NetworkBuilder {
|
|||||||
val notariesFuture = notaryDiscoveryFuture.thenCompose { copiedNotaries ->
|
val notariesFuture = notaryDiscoveryFuture.thenCompose { copiedNotaries ->
|
||||||
copiedNotaries
|
copiedNotaries
|
||||||
.map { copiedNotary ->
|
.map { copiedNotary ->
|
||||||
nodeBuilder.buildNode(copiedNotary).also(onNodeBuiltCallback)
|
nodeBuilder.buildNode(copiedNotary).thenAlsoAsync {
|
||||||
}.map { builtNotary ->
|
onNodeBuildStartCallback.invoke(it)
|
||||||
|
}
|
||||||
|
}.map { builtNotaryFuture ->
|
||||||
|
builtNotaryFuture.thenComposeAsync { builtNotary ->
|
||||||
|
onNodeBuiltCallback(builtNotary)
|
||||||
onNodePushStartCallback(builtNotary)
|
onNodePushStartCallback(builtNotary)
|
||||||
nodePusher.pushNode(builtNotary).thenApply { it.also(onNodePushedCallback) }
|
nodePusher.pushNode(builtNotary).thenAlsoAsync { pushedNotary ->
|
||||||
|
onNodePushedCallback(pushedNotary)
|
||||||
|
}
|
||||||
|
}
|
||||||
}.map { pushedNotary ->
|
}.map { pushedNotary ->
|
||||||
pushedNotary.thenApplyAsync { nodeInstantiator.createInstanceRequest(it).also { onNodeInstanceRequestedCallback.invoke(listOf(it)) } }
|
pushedNotary.thenApplyAsync {
|
||||||
|
nodeInstantiator.createInstanceRequest(it).also { onNodeInstanceRequestedCallback(listOf(it)) }
|
||||||
|
}
|
||||||
}.map { instanceRequest ->
|
}.map { instanceRequest ->
|
||||||
instanceRequest.thenComposeAsync { request ->
|
instanceRequest.thenComposeAsync { request ->
|
||||||
nodeInstantiator.instantiateNotaryInstance(request).thenApply { it.also(onNodeInstanceCallback) }
|
nodeInstantiator.instantiateNotaryInstance(request).thenApply { it.also(onNodeInstanceCallback) }
|
||||||
@ -185,17 +195,16 @@ private class NetworkBuilderImpl : NetworkBuilder {
|
|||||||
}
|
}
|
||||||
}.map { copiedNode: CopiedNode ->
|
}.map { copiedNode: CopiedNode ->
|
||||||
onNodeBuildStartCallback.invoke(copiedNode)
|
onNodeBuildStartCallback.invoke(copiedNode)
|
||||||
nodeBuilder.buildNode(copiedNode).let {
|
nodeBuilder.buildNode(copiedNode)
|
||||||
onNodeBuiltCallback.invoke(it)
|
}.map { builtNodeFuture ->
|
||||||
it
|
builtNodeFuture.thenComposeAsync { builtNode ->
|
||||||
|
onNodeBuiltCallback.invoke(builtNode)
|
||||||
|
nodePusher.pushNode(builtNode).thenAlsoAsync { pushedNode ->
|
||||||
|
onNodePushedCallback.invoke(pushedNode)
|
||||||
}
|
}
|
||||||
}.map { builtNode ->
|
|
||||||
nodePusher.pushNode(builtNode).thenApplyAsync {
|
|
||||||
onNodePushedCallback.invoke(it)
|
|
||||||
it
|
|
||||||
}
|
}
|
||||||
}.map { pushedNode ->
|
}.map { pushedNodeFuture ->
|
||||||
pushedNode.thenApplyAsync {
|
pushedNodeFuture.thenApplyAsync {
|
||||||
nodeInstantiator.createInstanceRequests(it, nodeCount).also(onNodeInstanceRequestedCallback)
|
nodeInstantiator.createInstanceRequests(it, nodeCount).also(onNodeInstanceRequestedCallback)
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -213,10 +222,10 @@ private class NetworkBuilderImpl : NetworkBuilder {
|
|||||||
}.toSingleFuture()
|
}.toSingleFuture()
|
||||||
}.thenCompose { it }.thenApplyAsync { it.flatten() }
|
}.thenCompose { it }.thenApplyAsync { it.flatten() }
|
||||||
|
|
||||||
return notariesFuture.thenCombineAsync(nodesFuture, { _, nodeInstances ->
|
return notariesFuture.thenCombineAsync(nodesFuture) { _, nodeInstances ->
|
||||||
context.networkInitiated = true
|
context.networkInitiated = true
|
||||||
nodeInstances to context
|
nodeInstances to context
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,3 +234,10 @@ fun <T> List<CompletableFuture<T>>.toSingleFuture(): CompletableFuture<List<T>>
|
|||||||
this.map { it.getNow(null) }
|
this.map { it.getNow(null) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> CompletableFuture<T>.thenAlsoAsync(consumer: (T) -> Unit): CompletableFuture<T> {
|
||||||
|
return this.thenApplyAsync {
|
||||||
|
consumer(it)
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package net.corda.bootstrapper.nodes
|
package net.corda.bootstrapper.nodes
|
||||||
|
|
||||||
|
import com.github.dockerjava.api.model.BuildResponseItem
|
||||||
|
import com.github.dockerjava.core.async.ResultCallbackTemplate
|
||||||
import com.github.dockerjava.core.command.BuildImageResultCallback
|
import com.github.dockerjava.core.command.BuildImageResultCallback
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
@ -11,6 +13,7 @@ import net.corda.node.services.config.NodeConfiguration
|
|||||||
import net.corda.node.services.config.parseAsNodeConfiguration
|
import net.corda.node.services.config.parseAsNodeConfiguration
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
open class NodeBuilder {
|
open class NodeBuilder {
|
||||||
|
|
||||||
@ -18,7 +21,10 @@ open class NodeBuilder {
|
|||||||
val LOG = LoggerFactory.getLogger(NodeBuilder::class.java)
|
val LOG = LoggerFactory.getLogger(NodeBuilder::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildNode(copiedNode: CopiedNode): BuiltNode {
|
fun buildNode(copiedNode: CopiedNode): CompletableFuture<BuiltNode> {
|
||||||
|
|
||||||
|
val future: CompletableFuture<BuiltNode> = CompletableFuture()
|
||||||
|
|
||||||
val localDockerClient = DockerUtils.createLocalDockerClient()
|
val localDockerClient = DockerUtils.createLocalDockerClient()
|
||||||
val copiedNodeConfig = copiedNode.copiedNodeConfig
|
val copiedNodeConfig = copiedNode.copiedNodeConfig
|
||||||
val nodeDir = copiedNodeConfig.parentFile
|
val nodeDir = copiedNodeConfig.parentFile
|
||||||
@ -27,15 +33,27 @@ open class NodeBuilder {
|
|||||||
}
|
}
|
||||||
val nodeConfig = ConfigFactory.parseFile(copiedNodeConfig)
|
val nodeConfig = ConfigFactory.parseFile(copiedNodeConfig)
|
||||||
LOG.info("starting to build docker image for: $nodeDir")
|
LOG.info("starting to build docker image for: $nodeDir")
|
||||||
val nodeImageId = localDockerClient.buildImageCmd()
|
localDockerClient.buildImageCmd()
|
||||||
.withDockerfile(File(nodeDir, "Dockerfile"))
|
.withDockerfile(File(nodeDir, "Dockerfile"))
|
||||||
.withBaseDirectory(nodeDir)
|
.withBaseDirectory(nodeDir).exec(object : ResultCallbackTemplate<BuildImageResultCallback, BuildResponseItem>() {
|
||||||
.exec(BuildImageResultCallback()).awaitImageId()
|
var result: BuildResponseItem? = null
|
||||||
LOG.info("finished building docker image for: $nodeDir with id: $nodeImageId")
|
override fun onNext(`object`: BuildResponseItem?) {
|
||||||
val config = nodeConfig.parseAsNodeConfigWithFallback(ConfigFactory.parseFile(copiedNode.configFile)).value()
|
this.result = `object`
|
||||||
return copiedNode.builtNode(config, nodeImageId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onError(throwable: Throwable?) {
|
||||||
|
future.completeExceptionally(throwable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete() {
|
||||||
|
super.onComplete()
|
||||||
|
LOG.info("finished building docker image for: $nodeDir with id: ${result?.imageId}")
|
||||||
|
val config = nodeConfig.parseAsNodeConfigWithFallback(ConfigFactory.parseFile(copiedNode.configFile)).value()
|
||||||
|
future.complete(copiedNode.builtNode(config, result?.imageId!!))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return future
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Config.parseAsNodeConfigWithFallback(preCopyConfig: Config): Validated<NodeConfiguration, Configuration.Validation.Error> {
|
fun Config.parseAsNodeConfigWithFallback(preCopyConfig: Config): Validated<NodeConfiguration, Configuration.Validation.Error> {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
# Base image from (http://phusion.github.io/baseimage-docker)
|
FROM openjdk:8u212-jre-alpine
|
||||||
FROM openjdk:8u151-jre-alpine
|
|
||||||
|
|
||||||
RUN apk upgrade --update && \
|
RUN apk upgrade --update && \
|
||||||
apk add --update --no-cache bash iputils && \
|
apk add --update --no-cache bash iputils && \
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Base image from (http://phusion.github.io/baseimage-docker)
|
# Base image from (http://phusion.github.io/baseimage-docker)
|
||||||
FROM openjdk:8u151-jre-alpine
|
FROM openjdk:8u212-jre-alpine
|
||||||
|
|
||||||
RUN apk upgrade --update && \
|
RUN apk upgrade --update && \
|
||||||
apk add --update --no-cache bash iputils && \
|
apk add --update --no-cache bash iputils && \
|
||||||
|
Loading…
Reference in New Issue
Block a user