Particular / NServiceBus

Build, version, and monitor better microservices with the most powerful service platform for .NET
https://particular.net/nservicebus/
Other
2.09k stars 648 forks source link

Should resolve address machine name using DNS #898

Closed johnsimons closed 9 years ago

johnsimons commented 11 years ago

If a user enable MSMQ to work with DNS aliases we need to ensure that the endpoint machine name is resolved via DNS and then check that against the loopback address.

Here is all the detail from a SO question:

I hit the roadblock today. In our org, all the deployments are done by TFS Build. Where the each of the NSB Host components are packaged and deployed by the build portal. When we try to use the Scale-Out features of NSB, where we have to install the same components with Master and Worker profiles. We managed Master & Worker installers by passing the required arguments when we package it. To simplify the process we planned to use one single Configuration file for both Master and Worker where we kept the MasterNode configuration for both master and worker. All fine! It worked really well.

As per the policy, we should not use the server names on the configuration files and we have to use the DNS aliases on our Config file. We achieved it by enabling the MSMQ work on top of DNS aliases.

Now the real issue starts, NServiceBus.Master profiles appends the Node value on the input queue. When we use the DNS aliases as Node it throws the following exception.

System.Exception: Exception when starting endpoint, error has been logged. Reason: Input queue [somequeue@some-dns.bus] must be on the same machine as this process [SOMEDITSERVER01]. ---> System.InvalidOperationException : Input queue [somequeue@some-dns.bus] must be on the same machine as this process [SOMEDITSERVER01]. at NServiceBus.Unicast.Queuing.Msmq.MsmqMessageReceiver.Init(Address address, Boolean transactional) at NServiceBus.Unicast.Transport.Transactional.TransactionalTransport.NServiceBus.Unicast.Transport.ITransport.Start(Address address) at NServiceBus.Unicast.UnicastBus.NServiceBus.IStartableBus.Start(Action startupAction) at NServiceBus.Hosting.GenericHost.Start()

--- End of inner exception stack trace --- at NServiceBus.Hosting.GenericHost.Start() at Magnum.StateMachine.EventActionList`1.Execute(T stateMachine, Event event, Object parameter)

--- End of inner exception stack trace --- at Magnum.StateMachine.ExceptionActionDictionary1.HandleException(T stateMachine, Event event, Object parameter, Exception exception)
at Magnum.StateMachine.EventActionList1.Execute(T stateMachine, Event event, Object parameter) at Magnum.StateMachine.State1.RaiseEvent(T instance, BasicEvent1 eevent, Object value) at Magnum.StateMachine.StateMachine`1.RaiseEvent(Event raised) at Topshelf.Internal.ServiceControllerProxy.Start() at Topshelf.Internal.ServiceCoordinator.Start() at Topshelf.Internal.Hosts.ConsoleHost.Run() at NServiceBus.Hosting.Windows.Program.Main(String[] args)

Questions:

Why is NSB appending the MasterNode value on the input queues & other queues, when NSB is strictly looking for the current MachineName as valid server name for current input queue? Why not NSB just ignore the MasterNode values when it runs with NServiceBus.Master or NServiceBus.Distributor?

If NSB still wanted to append the MasterNode value on input queue… Why NSB is not resolving the DNS names, instead it limits with the validation with current MachineName?

var configSection = Configure.GetConfigSection<MasterNodeConfig>();
if (configSection == null)
{
    return;
}
var ipAddressesOfNode = Dns.GetHostEntry(configSection.Node).AddressList.Select(ip => ip.ToString()).ToArray();
var ipAddressesOfHost = Dns.GetHostEntry(Environment.MachineName).AddressList.Select(ip => ip.ToString()).ToArray();
if (ipAddressesOfHost.Any(ipAddressesOfNode.Contains))
{
    //Valid DNS Name
}
Finally we end-up with following option,

1.Failed Approach: Alter the MasterNodeConfig’s Node value on the IHandleProfile. I liked this approach but it has few drawbacks. It wont work, since MasterNodeConfig is not overriden the default behavior of IsReadonly() and it will throw error. If you use integration profile, during the installation it won’t create the Worker & Distributor queue

internal class MasterNodeConfigSetup : IHandleProfile<Master> 
{
   public void ProfileActivated()
   {
     var configSection = Configure.GetConfigSection<MasterNodeConfig>();
     configSection.Node = Environment.MachineName;
   } 
}
There is hack to bypass the runtime error created by the above code. But if you manually take care other queue creation we can use this;

var field = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
if (field != null)
{
    field.SetValue(configSection, false);
    configSection.Node = Environment.MachineName;
}
2.Keep the two different Config files for worker and master & package it. Lot of work looks feasible.

3.Remove the MasterNodeConfig during the Master component deployment.

I am not against to NSB, I love NSB. I am just expressing my frustration, wanted to know the reason WHY! Why it is appending MasterNode value & why it is just validating with Environemnt instead resolving it.

I am very much open to accept any suggestions from you.
andreasohlund commented 11 years ago

Since MSMQ does support remote transactional reads now should we also make this a Log.Error|Warn to avoid blocking users if the validation is flawed?

andreasohlund commented 11 years ago

We're doing similar validations in a few places. Make sure to consolidate them when we fix this

johnsimons commented 11 years ago

Just so that I understand the scope of this change:

andreasohlund commented 11 years ago

1: is done so there is now a workaround (use RuntimeEnvironment.MachineNameAction to override the machine name)

SimonCropp commented 9 years ago

@johnsimons should this be in the distributor repo?

johnsimons commented 9 years ago

@SimonCropp I'm pretty sure this was fixed in https://github.com/Particular/NServiceBus/commit/301eb6783cce2e61c3afac5e23f9a66c0f493f46?diff=unified#diff-7e4fb8501d2f0d57e9d2b1318d6d1267R73, thoughts?

SimonCropp commented 9 years ago

@johnsimons looks like it. so close?