mirror of
https://github.com/corda/corda.git
synced 2025-06-18 23:28:21 +00:00
node: Driver network map starts parallel with other nodes, uses executor service, pre-create most artemis queues
This commit is contained in:
@ -7,20 +7,23 @@ import net.corda.node.services.api.RegulatorService
|
|||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
||||||
import net.corda.node.services.transactions.SimpleNotaryService
|
import net.corda.node.services.transactions.SimpleNotaryService
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
|
|
||||||
class DriverTests {
|
class DriverTests {
|
||||||
companion object {
|
companion object {
|
||||||
|
val executorService = Executors.newScheduledThreadPool(2)
|
||||||
|
|
||||||
fun nodeMustBeUp(nodeInfo: NodeInfo) {
|
fun nodeMustBeUp(nodeInfo: NodeInfo) {
|
||||||
val hostAndPort = ArtemisMessagingComponent.toHostAndPort(nodeInfo.address)
|
val hostAndPort = ArtemisMessagingComponent.toHostAndPort(nodeInfo.address)
|
||||||
// Check that the port is bound
|
// Check that the port is bound
|
||||||
addressMustBeBound(hostAndPort)
|
addressMustBeBound(executorService, hostAndPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun nodeMustBeDown(nodeInfo: NodeInfo) {
|
fun nodeMustBeDown(nodeInfo: NodeInfo) {
|
||||||
val hostAndPort = ArtemisMessagingComponent.toHostAndPort(nodeInfo.address)
|
val hostAndPort = ArtemisMessagingComponent.toHostAndPort(nodeInfo.address)
|
||||||
// Check that the port is bound
|
// Check that the port is bound
|
||||||
addressMustNotBeBound(hostAndPort)
|
addressMustNotBeBound(executorService, hostAndPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,16 +114,15 @@ class RaftValidatingNotaryServiceTests : DriverBasedTest() {
|
|||||||
waitFor()
|
waitFor()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pay ourselves another 10x5 pounds
|
// Pay ourselves another 20x5 pounds
|
||||||
for (i in 1..10) {
|
for (i in 1..20) {
|
||||||
val payHandle = aliceProxy.startFlow(::CashFlow, CashCommand.PayCash(5.POUNDS.issuedBy(alice.legalIdentity.ref(0)), alice.legalIdentity))
|
val payHandle = aliceProxy.startFlow(::CashFlow, CashCommand.PayCash(5.POUNDS.issuedBy(alice.legalIdentity.ref(0)), alice.legalIdentity))
|
||||||
require(payHandle.returnValue.toBlocking().first() is CashFlowResult.Success)
|
require(payHandle.returnValue.toBlocking().first() is CashFlowResult.Success)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Artemis still dispatches some requests to the dead notary but all others should go through.
|
|
||||||
val notarisationsPerNotary = HashMap<Party, Int>()
|
val notarisationsPerNotary = HashMap<Party, Int>()
|
||||||
notaryStateMachines.expectEvents(isStrict = false) {
|
notaryStateMachines.expectEvents(isStrict = false) {
|
||||||
replicate<Pair<NodeInfo, StateMachineUpdate>>(15) {
|
replicate<Pair<NodeInfo, StateMachineUpdate>>(30) {
|
||||||
expect(match = { it.second is StateMachineUpdate.Added }) {
|
expect(match = { it.second is StateMachineUpdate.Added }) {
|
||||||
val (notary, update) = it
|
val (notary, update) = it
|
||||||
update as StateMachineUpdate.Added
|
update as StateMachineUpdate.Added
|
||||||
|
@ -17,9 +17,9 @@ import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.NET
|
|||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.NOTIFICATIONS_ADDRESS
|
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.NOTIFICATIONS_ADDRESS
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.P2P_QUEUE
|
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.P2P_QUEUE
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.PEERS_PREFIX
|
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.PEERS_PREFIX
|
||||||
|
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.RPC_QUEUE_REMOVALS_QUEUE
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.RPC_REQUESTS_QUEUE
|
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.RPC_REQUESTS_QUEUE
|
||||||
import net.corda.node.services.messaging.CordaRPCClientImpl
|
import net.corda.node.services.messaging.CordaRPCClientImpl
|
||||||
import net.corda.node.services.messaging.NodeMessagingClient.Companion.RPC_QUEUE_REMOVALS_QUEUE
|
|
||||||
import net.corda.testing.messaging.SimpleMQClient
|
import net.corda.testing.messaging.SimpleMQClient
|
||||||
import net.corda.testing.node.NodeBasedTest
|
import net.corda.testing.node.NodeBasedTest
|
||||||
import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException
|
import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException
|
||||||
|
@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule
|
|||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import com.google.common.util.concurrent.Futures
|
import com.google.common.util.concurrent.Futures
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigRenderOptions
|
import com.typesafe.config.ConfigRenderOptions
|
||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
@ -33,14 +34,13 @@ import java.time.Instant
|
|||||||
import java.time.ZoneOffset.UTC
|
import java.time.ZoneOffset.UTC
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
import java.util.concurrent.Future
|
import java.util.concurrent.Future
|
||||||
|
import java.util.concurrent.ScheduledExecutorService
|
||||||
|
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||||
import java.util.concurrent.TimeUnit.SECONDS
|
import java.util.concurrent.TimeUnit.SECONDS
|
||||||
import java.util.concurrent.TimeoutException
|
import java.util.concurrent.TimeoutException
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import kotlin.concurrent.thread
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file defines a small "Driver" DSL for starting up nodes that is only intended for development, demos and tests.
|
* This file defines a small "Driver" DSL for starting up nodes that is only intended for development, demos and tests.
|
||||||
@ -67,7 +67,7 @@ interface DriverDSLExposedInterface {
|
|||||||
fun startNode(providedName: String? = null,
|
fun startNode(providedName: String? = null,
|
||||||
advertisedServices: Set<ServiceInfo> = emptySet(),
|
advertisedServices: Set<ServiceInfo> = emptySet(),
|
||||||
rpcUsers: List<User> = emptyList(),
|
rpcUsers: List<User> = emptyList(),
|
||||||
customOverrides: Map<String, Any?> = emptyMap()): Future<NodeHandle>
|
customOverrides: Map<String, Any?> = emptyMap()): ListenableFuture<NodeHandle>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a distributed notary cluster.
|
* Starts a distributed notary cluster.
|
||||||
@ -198,8 +198,8 @@ fun getTimestampAsDirectoryName(): String {
|
|||||||
return DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(UTC).format(Instant.now())
|
return DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(UTC).format(Instant.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addressMustBeBound(hostAndPort: HostAndPort) {
|
fun addressMustBeBound(executorService: ScheduledExecutorService, hostAndPort: HostAndPort): ListenableFuture<Unit> {
|
||||||
poll("address $hostAndPort to bind") {
|
return poll(executorService, "address $hostAndPort to bind") {
|
||||||
try {
|
try {
|
||||||
Socket(hostAndPort.hostText, hostAndPort.port).close()
|
Socket(hostAndPort.hostText, hostAndPort.port).close()
|
||||||
Unit
|
Unit
|
||||||
@ -209,8 +209,8 @@ fun addressMustBeBound(hostAndPort: HostAndPort) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addressMustNotBeBound(hostAndPort: HostAndPort) {
|
fun addressMustNotBeBound(executorService: ScheduledExecutorService, hostAndPort: HostAndPort): ListenableFuture<Unit> {
|
||||||
poll("address $hostAndPort to unbind") {
|
return poll(executorService, "address $hostAndPort to unbind") {
|
||||||
try {
|
try {
|
||||||
Socket(hostAndPort.hostText, hostAndPort.port).close()
|
Socket(hostAndPort.hostText, hostAndPort.port).close()
|
||||||
null
|
null
|
||||||
@ -220,18 +220,36 @@ fun addressMustNotBeBound(hostAndPort: HostAndPort) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <A> poll(pollName: String, pollIntervalMs: Long = 500, warnCount: Int = 120, f: () -> A?): A {
|
private fun <A> poll(
|
||||||
|
executorService: ScheduledExecutorService,
|
||||||
|
pollName: String,
|
||||||
|
pollIntervalMs: Long = 500,
|
||||||
|
warnCount: Int = 120,
|
||||||
|
check: () -> A?
|
||||||
|
): ListenableFuture<A> {
|
||||||
|
val initialResult = check()
|
||||||
|
val resultFuture = SettableFuture.create<A>()
|
||||||
|
if (initialResult != null) {
|
||||||
|
resultFuture.set(initialResult)
|
||||||
|
return resultFuture
|
||||||
|
}
|
||||||
var counter = 0
|
var counter = 0
|
||||||
var result = f()
|
fun schedulePoll() {
|
||||||
while (result == null) {
|
executorService.schedule({
|
||||||
if (counter == warnCount) {
|
counter++
|
||||||
log.warn("Been polling $pollName for ${pollIntervalMs * warnCount / 1000.0} seconds...")
|
if (counter == warnCount) {
|
||||||
}
|
log.warn("Been polling $pollName for ${pollIntervalMs * warnCount / 1000.0} seconds...")
|
||||||
counter = (counter % warnCount) + 1
|
}
|
||||||
Thread.sleep(pollIntervalMs)
|
val result = check()
|
||||||
result = f()
|
if (result == null) {
|
||||||
|
schedulePoll()
|
||||||
|
} else {
|
||||||
|
resultFuture.set(result)
|
||||||
|
}
|
||||||
|
}, pollIntervalMs, MILLISECONDS)
|
||||||
}
|
}
|
||||||
return result
|
schedulePoll()
|
||||||
|
return resultFuture
|
||||||
}
|
}
|
||||||
|
|
||||||
open class DriverDSL(
|
open class DriverDSL(
|
||||||
@ -241,13 +259,13 @@ open class DriverDSL(
|
|||||||
val useTestClock: Boolean,
|
val useTestClock: Boolean,
|
||||||
val isDebug: Boolean
|
val isDebug: Boolean
|
||||||
) : DriverDSLInternalInterface {
|
) : DriverDSLInternalInterface {
|
||||||
|
private val executorService: ScheduledExecutorService = Executors.newScheduledThreadPool(2)
|
||||||
private val networkMapName = "NetworkMapService"
|
private val networkMapName = "NetworkMapService"
|
||||||
private val networkMapAddress = portAllocation.nextHostAndPort()
|
private val networkMapAddress = portAllocation.nextHostAndPort()
|
||||||
|
|
||||||
class State {
|
class State {
|
||||||
val registeredProcesses = LinkedList<Process>()
|
val registeredProcesses = LinkedList<Process>()
|
||||||
val clients = LinkedList<NodeMessagingClient>()
|
val clients = LinkedList<NodeMessagingClient>()
|
||||||
var localServer: ArtemisMessagingServer? = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val state = ThreadBox(State())
|
private val state = ThreadBox(State())
|
||||||
@ -276,11 +294,10 @@ open class DriverDSL(
|
|||||||
clients.forEach {
|
clients.forEach {
|
||||||
it.stop()
|
it.stop()
|
||||||
}
|
}
|
||||||
localServer?.stop()
|
|
||||||
registeredProcesses.forEach(Process::destroy)
|
registeredProcesses.forEach(Process::destroy)
|
||||||
}
|
}
|
||||||
/** Wait 5 seconds, then [Process.destroyForcibly] */
|
/** Wait 5 seconds, then [Process.destroyForcibly] */
|
||||||
val finishedFuture = future {
|
val finishedFuture = executorService.submit {
|
||||||
waitForAllNodesToFinish()
|
waitForAllNodesToFinish()
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -295,10 +312,8 @@ open class DriverDSL(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that we shut down properly
|
// Check that we shut down properly
|
||||||
state.locked {
|
addressMustNotBeBound(executorService, networkMapAddress).get()
|
||||||
localServer?.run { addressMustNotBeBound(myHostPort) }
|
executorService.shutdown()
|
||||||
}
|
|
||||||
addressMustNotBeBound(networkMapAddress)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun queryNodeInfo(webAddress: HostAndPort): NodeInfo? {
|
private fun queryNodeInfo(webAddress: HostAndPort): NodeInfo? {
|
||||||
@ -353,10 +368,9 @@ open class DriverDSL(
|
|||||||
configOverrides = configOverrides
|
configOverrides = configOverrides
|
||||||
)
|
)
|
||||||
|
|
||||||
return future {
|
return startNode(executorService, FullNodeConfiguration(config), quasarJarPath, debugPort).map {
|
||||||
val process = DriverDSL.startNode(FullNodeConfiguration(config), quasarJarPath, debugPort)
|
registerProcess(it)
|
||||||
registerProcess(process)
|
NodeHandle(queryNodeInfo(apiAddress)!!, config, it)
|
||||||
NodeHandle(queryNodeInfo(apiAddress)!!, config, process)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +409,7 @@ open class DriverDSL(
|
|||||||
startNetworkMapService()
|
startNetworkMapService()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startNetworkMapService() {
|
private fun startNetworkMapService(): ListenableFuture<Unit> {
|
||||||
val apiAddress = portAllocation.nextHostAndPort()
|
val apiAddress = portAllocation.nextHostAndPort()
|
||||||
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
|
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
|
||||||
|
|
||||||
@ -414,7 +428,9 @@ open class DriverDSL(
|
|||||||
)
|
)
|
||||||
|
|
||||||
log.info("Starting network-map-service")
|
log.info("Starting network-map-service")
|
||||||
registerProcess(startNode(FullNodeConfiguration(config), quasarJarPath, debugPort))
|
return startNode(executorService, FullNodeConfiguration(config), quasarJarPath, debugPort).map {
|
||||||
|
registerProcess(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -428,10 +444,11 @@ open class DriverDSL(
|
|||||||
fun <A> pickA(array: Array<A>): A = array[Math.abs(Random().nextInt()) % array.size]
|
fun <A> pickA(array: Array<A>): A = array[Math.abs(Random().nextInt()) % array.size]
|
||||||
|
|
||||||
private fun startNode(
|
private fun startNode(
|
||||||
|
executorService: ScheduledExecutorService,
|
||||||
nodeConf: FullNodeConfiguration,
|
nodeConf: FullNodeConfiguration,
|
||||||
quasarJarPath: String,
|
quasarJarPath: String,
|
||||||
debugPort: Int?
|
debugPort: Int?
|
||||||
): Process {
|
): ListenableFuture<Process> {
|
||||||
// Write node.conf
|
// Write node.conf
|
||||||
writeConfig(nodeConf.basedir, "node.conf", nodeConf.config)
|
writeConfig(nodeConf.basedir, "node.conf", nodeConf.config)
|
||||||
|
|
||||||
@ -454,13 +471,13 @@ open class DriverDSL(
|
|||||||
builder.inheritIO()
|
builder.inheritIO()
|
||||||
builder.directory(nodeConf.basedir.toFile())
|
builder.directory(nodeConf.basedir.toFile())
|
||||||
val process = builder.start()
|
val process = builder.start()
|
||||||
addressMustBeBound(nodeConf.artemisAddress)
|
return Futures.allAsList(
|
||||||
// TODO There is a race condition here. Even though the messaging address is bound it may be the case that
|
addressMustBeBound(executorService, nodeConf.artemisAddress),
|
||||||
// the handlers for the advertised services are not yet registered. A hacky workaround is that we wait for
|
// TODO There is a race condition here. Even though the messaging address is bound it may be the case that
|
||||||
// the web api address to be bound as well, as that starts after the services. Needs rethinking.
|
// the handlers for the advertised services are not yet registered. A hacky workaround is that we wait for
|
||||||
addressMustBeBound(nodeConf.webAddress)
|
// the web api address to be bound as well, as that starts after the services. Needs rethinking.
|
||||||
|
addressMustBeBound(executorService, nodeConf.webAddress)
|
||||||
return process
|
).map { process }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -469,4 +486,3 @@ fun writeConfig(path: Path, filename: String, config: Config) {
|
|||||||
path.toFile().mkdirs()
|
path.toFile().mkdirs()
|
||||||
File("$path/$filename").writeText(config.root().render(ConfigRenderOptions.concise()))
|
File("$path/$filename").writeText(config.root().render(ConfigRenderOptions.concise()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ class Node(override val configuration: FullNodeConfiguration, networkMapAddress:
|
|||||||
runOnStop += Runnable { messageBroker?.stop() }
|
runOnStop += Runnable { messageBroker?.stop() }
|
||||||
start()
|
start()
|
||||||
if (networkMapService is NetworkMapAddress) {
|
if (networkMapService is NetworkMapAddress) {
|
||||||
bridgeToNetworkMapService(networkMapService)
|
deployBridgeIfAbsent(networkMapService.queueName, networkMapService.hostAndPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,10 +39,11 @@ abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
|
|||||||
const val CLIENTS_PREFIX = "clients."
|
const val CLIENTS_PREFIX = "clients."
|
||||||
const val P2P_QUEUE = "p2p.inbound"
|
const val P2P_QUEUE = "p2p.inbound"
|
||||||
const val RPC_REQUESTS_QUEUE = "rpc.requests"
|
const val RPC_REQUESTS_QUEUE = "rpc.requests"
|
||||||
|
const val RPC_QUEUE_REMOVALS_QUEUE = "rpc.qremovals"
|
||||||
const val NOTIFICATIONS_ADDRESS = "${INTERNAL_PREFIX}activemq.notifications"
|
const val NOTIFICATIONS_ADDRESS = "${INTERNAL_PREFIX}activemq.notifications"
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val NETWORK_MAP_ADDRESS = SimpleString("${INTERNAL_PREFIX}networkmap")
|
val NETWORK_MAP_ADDRESS = "${INTERNAL_PREFIX}networkmap"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assuming the passed in target address is actually an ArtemisAddress will extract the host and port of the node. This should
|
* Assuming the passed in target address is actually an ArtemisAddress will extract the host and port of the node. This should
|
||||||
@ -57,16 +58,16 @@ abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected interface ArtemisAddress : MessageRecipients {
|
interface ArtemisAddress : MessageRecipients {
|
||||||
val queueName: SimpleString
|
val queueName: SimpleString
|
||||||
}
|
}
|
||||||
|
|
||||||
protected interface ArtemisPeerAddress : ArtemisAddress, SingleMessageRecipient {
|
interface ArtemisPeerAddress : ArtemisAddress, SingleMessageRecipient {
|
||||||
val hostAndPort: HostAndPort
|
val hostAndPort: HostAndPort
|
||||||
}
|
}
|
||||||
|
|
||||||
data class NetworkMapAddress(override val hostAndPort: HostAndPort) : SingleMessageRecipient, ArtemisPeerAddress {
|
data class NetworkMapAddress(override val hostAndPort: HostAndPort) : SingleMessageRecipient, ArtemisPeerAddress {
|
||||||
override val queueName: SimpleString get() = NETWORK_MAP_ADDRESS
|
override val queueName = SimpleString(NETWORK_MAP_ADDRESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,6 +25,7 @@ import net.corda.node.services.messaging.ArtemisMessagingServer.NodeLoginModule.
|
|||||||
import org.apache.activemq.artemis.api.core.SimpleString
|
import org.apache.activemq.artemis.api.core.SimpleString
|
||||||
import org.apache.activemq.artemis.core.config.BridgeConfiguration
|
import org.apache.activemq.artemis.core.config.BridgeConfiguration
|
||||||
import org.apache.activemq.artemis.core.config.Configuration
|
import org.apache.activemq.artemis.core.config.Configuration
|
||||||
|
import org.apache.activemq.artemis.core.config.CoreQueueConfiguration
|
||||||
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl
|
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl
|
||||||
import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration
|
import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration
|
||||||
import org.apache.activemq.artemis.core.security.Role
|
import org.apache.activemq.artemis.core.security.Role
|
||||||
@ -105,14 +106,6 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
running = false
|
running = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bridgeToNetworkMapService(networkMapService: NetworkMapAddress) {
|
|
||||||
val query = activeMQServer.queueQuery(NETWORK_MAP_ADDRESS)
|
|
||||||
if (!query.isExists) {
|
|
||||||
activeMQServer.createQueue(NETWORK_MAP_ADDRESS, NETWORK_MAP_ADDRESS, null, true, false)
|
|
||||||
}
|
|
||||||
deployBridgeIfAbsent(networkMapService.queueName, networkMapService.hostAndPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The bridge will be created automatically when the queues are created, however, this is not the case when the network map restarted.
|
* The bridge will be created automatically when the queues are created, however, this is not the case when the network map restarted.
|
||||||
* The queues are restored from the journal, and because the queues are added before we register the callback handler, this method will never get called for existing queues.
|
* The queues are restored from the journal, and because the queues are added before we register the callback handler, this method will never get called for existing queues.
|
||||||
@ -225,6 +218,36 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
// password is changed from the default (as warned in the docs). Since we don't need this feature we turn it off
|
// password is changed from the default (as warned in the docs). Since we don't need this feature we turn it off
|
||||||
// by having its password be an unknown securely random 128-bit value.
|
// by having its password be an unknown securely random 128-bit value.
|
||||||
clusterPassword = BigInteger(128, newSecureRandom()).toString(16)
|
clusterPassword = BigInteger(128, newSecureRandom()).toString(16)
|
||||||
|
|
||||||
|
queueConfigurations.addAll(listOf(
|
||||||
|
CoreQueueConfiguration().apply {
|
||||||
|
address = NETWORK_MAP_ADDRESS
|
||||||
|
name = NETWORK_MAP_ADDRESS
|
||||||
|
isDurable = true
|
||||||
|
},
|
||||||
|
CoreQueueConfiguration().apply {
|
||||||
|
address = P2P_QUEUE
|
||||||
|
name = P2P_QUEUE
|
||||||
|
isDurable = true
|
||||||
|
},
|
||||||
|
// Create an RPC queue: this will service locally connected clients only (not via a bridge) and those
|
||||||
|
// clients must have authenticated. We could use a single consumer for everything and perhaps we should,
|
||||||
|
// but these queues are not worth persisting.
|
||||||
|
CoreQueueConfiguration().apply {
|
||||||
|
name = RPC_REQUESTS_QUEUE
|
||||||
|
address = RPC_REQUESTS_QUEUE
|
||||||
|
isDurable = false
|
||||||
|
},
|
||||||
|
// The custom name for the queue is intentional - we may wish other things to subscribe to the
|
||||||
|
// NOTIFICATIONS_ADDRESS with different filters in future
|
||||||
|
CoreQueueConfiguration().apply {
|
||||||
|
name = RPC_QUEUE_REMOVALS_QUEUE
|
||||||
|
address = NOTIFICATIONS_ADDRESS
|
||||||
|
isDurable = false
|
||||||
|
filterString = "_AMQ_NotifType = 1"
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
configureAddressSecurity()
|
configureAddressSecurity()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +307,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
|
|
||||||
private fun bridgeExists(name: String) = activeMQServer.clusterManager.bridges.containsKey(name)
|
private fun bridgeExists(name: String) = activeMQServer.clusterManager.bridges.containsKey(name)
|
||||||
|
|
||||||
private fun deployBridgeIfAbsent(queueName: SimpleString, hostAndPort: HostAndPort) {
|
fun deployBridgeIfAbsent(queueName: SimpleString, hostAndPort: HostAndPort) {
|
||||||
if (!connectorExists(hostAndPort)) {
|
if (!connectorExists(hostAndPort)) {
|
||||||
addConnector(hostAndPort)
|
addConnector(hostAndPort)
|
||||||
}
|
}
|
||||||
|
@ -67,8 +67,6 @@ class NodeMessagingClient(override val config: NodeConfiguration,
|
|||||||
const val TOPIC_PROPERTY = "platform-topic"
|
const val TOPIC_PROPERTY = "platform-topic"
|
||||||
const val SESSION_ID_PROPERTY = "session-id"
|
const val SESSION_ID_PROPERTY = "session-id"
|
||||||
|
|
||||||
const val RPC_QUEUE_REMOVALS_QUEUE = "rpc.qremovals"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This should be the only way to generate an ArtemisAddress and that only of the remote NetworkMapService node.
|
* This should be the only way to generate an ArtemisAddress and that only of the remote NetworkMapService node.
|
||||||
* All other addresses come from the NetworkMapCache, or myAddress below.
|
* All other addresses come from the NetworkMapCache, or myAddress below.
|
||||||
@ -136,7 +134,6 @@ class NodeMessagingClient(override val config: NodeConfiguration,
|
|||||||
producer = session.createProducer()
|
producer = session.createProducer()
|
||||||
|
|
||||||
// Create a queue, consumer and producer for handling P2P network messages.
|
// Create a queue, consumer and producer for handling P2P network messages.
|
||||||
createQueueIfAbsent(SimpleString(P2P_QUEUE))
|
|
||||||
p2pConsumer = makeP2PConsumer(session, true)
|
p2pConsumer = makeP2PConsumer(session, true)
|
||||||
networkMapRegistrationFuture.success {
|
networkMapRegistrationFuture.success {
|
||||||
state.locked {
|
state.locked {
|
||||||
@ -150,13 +147,6 @@ class NodeMessagingClient(override val config: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an RPC queue and consumer: this will service locally connected clients only (not via a
|
|
||||||
// bridge) and those clients must have authenticated. We could use a single consumer for everything
|
|
||||||
// and perhaps we should, but these queues are not worth persisting.
|
|
||||||
session.createTemporaryQueue(RPC_REQUESTS_QUEUE, RPC_REQUESTS_QUEUE)
|
|
||||||
// The custom name for the queue is intentional - we may wish other things to subscribe to the
|
|
||||||
// NOTIFICATIONS_ADDRESS with different filters in future
|
|
||||||
session.createTemporaryQueue(NOTIFICATIONS_ADDRESS, RPC_QUEUE_REMOVALS_QUEUE, "_AMQ_NotifType = 1")
|
|
||||||
rpcConsumer = session.createConsumer(RPC_REQUESTS_QUEUE)
|
rpcConsumer = session.createConsumer(RPC_REQUESTS_QUEUE)
|
||||||
rpcNotificationConsumer = session.createConsumer(RPC_QUEUE_REMOVALS_QUEUE)
|
rpcNotificationConsumer = session.createConsumer(RPC_QUEUE_REMOVALS_QUEUE)
|
||||||
rpcDispatcher = createRPCDispatcher(rpcOps, userService, config.myLegalName)
|
rpcDispatcher = createRPCDispatcher(rpcOps, userService, config.myLegalName)
|
||||||
|
Reference in New Issue
Block a user