Browse Source

Also use advertised IP address for development clustering.

pull/352/head
Sebastian Stehle 7 years ago
parent
commit
04e1801f0b
  1. 42
      src/Squidex.Infrastructure/IPAddressComparer.cs
  2. 45
      src/Squidex/Config/Orleans/Helper.cs
  3. 71
      src/Squidex/Config/Orleans/OrleansServices.cs
  4. 44
      tests/Squidex.Infrastructure.Tests/IPAddressComparerTests.cs

42
src/Squidex.Infrastructure/IPAddressComparer.cs

@ -0,0 +1,42 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.Net;
namespace Squidex.Infrastructure
{
public sealed class IPAddressComparer : IComparer<IPAddress>
{
public static readonly IPAddressComparer Instance = new IPAddressComparer();
private IPAddressComparer()
{
}
public int Compare(IPAddress x, IPAddress y)
{
var lbytes = x.GetAddressBytes();
var rbytes = y.GetAddressBytes();
if (lbytes.Length != rbytes.Length)
{
return lbytes.Length - rbytes.Length;
}
for (var i = 0; i < lbytes.Length; i++)
{
if (lbytes[i] != rbytes[i])
{
return lbytes[i] - rbytes[i];
}
}
return 0;
}
}
}

45
src/Squidex/Config/Orleans/Helper.cs

@ -0,0 +1,45 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using Squidex.Infrastructure;
namespace Squidex.Config.Orleans
{
public static class Helper
{
internal static async Task<IPAddress> ResolveIPAddressAsync(string addressOrHost, AddressFamily family)
{
var loopback = family == AddressFamily.InterNetwork ? IPAddress.Loopback : IPAddress.IPv6Loopback;
if (addressOrHost.Equals("loopback", StringComparison.OrdinalIgnoreCase))
{
return loopback;
}
if (IPAddress.TryParse(addressOrHost, out var address))
{
return address;
}
var candidates = await Dns.GetHostAddressesAsync(addressOrHost);
var chosen = candidates.OrderBy(x => x, IPAddressComparer.Instance).FirstOrDefault();
if (chosen == null)
{
throw new ConfigurationException($"Hostname {addressOrHost} with family {family} is not a valid IP address or DNS name");
}
return chosen;
}
}
}

71
src/Squidex/Config/Orleans/OrleansServices.cs

@ -6,11 +6,13 @@
// ==========================================================================
using System.Net;
using System.Net.Sockets;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Orleans;
using Orleans.Configuration;
using Orleans.Hosting;
using Orleans.Providers.MongoDB.Configuration;
using OrleansDashboard;
using Squidex.Domain.Apps.Entities;
using Squidex.Infrastructure;
@ -28,28 +30,28 @@ namespace Squidex.Config.Orleans
{
builder.ConfigureServices(siloServices =>
{
siloServices.Configure<ClusterOptions>(options =>
{
options.Configure();
siloServices.AddSingleton<IIncomingGrainCallFilter, LocalCacheFilter>();
});
siloServices.Configure<ProcessExitHandlingOptions>(options =>
builder.ConfigureApplicationParts(parts =>
{
options.FastKillOnProcessExit = false;
parts.AddApplicationPart(SquidexEntities.Assembly);
parts.AddApplicationPart(SquidexInfrastructure.Assembly);
});
siloServices.Configure<DashboardOptions>(options =>
builder.Configure<ClusterOptions>(options =>
{
options.HideTrace = true;
options.Configure();
});
siloServices.AddSingleton<IIncomingGrainCallFilter, LocalCacheFilter>();
builder.Configure<ProcessExitHandlingOptions>(options =>
{
options.FastKillOnProcessExit = false;
});
builder.ConfigureApplicationParts(parts =>
builder.Configure<DashboardOptions>(options =>
{
parts.AddApplicationPart(SquidexEntities.Assembly);
parts.AddApplicationPart(SquidexInfrastructure.Assembly);
options.HideTrace = true;
});
builder.UseDashboard(options =>
@ -57,30 +59,34 @@ namespace Squidex.Config.Orleans
options.HostSelf = false;
});
var gatewayPort = config.GetOptionalValue("orleans:gatewayPort", 40000);
var orleansPortSilo = config.GetOptionalValue("orleans:siloPort", 11111);
var orleansPortGateway = config.GetOptionalValue("orleans:gatewayPort", 40000);
var siloPort = config.GetOptionalValue("orleans:siloPort", 11111);
var address = Helper.ResolveIPAddressAsync(Dns.GetHostName(), AddressFamily.InterNetwork).Result;
builder.ConfigureEndpoints(
address,
orleansPortSilo,
orleansPortGateway,
true);
config.ConfigureByOption("orleans:clustering", new Alternatives
{
["MongoDB"] = () =>
{
builder.ConfigureEndpoints(Dns.GetHostName(), siloPort, gatewayPort, listenOnAnyHostAddress: true);
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration");
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database");
builder.UseMongoDBClustering(options =>
{
options.ConnectionString = mongoConfiguration;
options.CollectionPrefix = "Orleans_";
options.DatabaseName = mongoDatabaseName;
options.Configure(config);
});
},
["Development"] = () =>
{
builder.UseLocalhostClustering(siloPort, gatewayPort, null, Constants.OrleansClusterId, Constants.OrleansClusterId);
builder.Configure<ClusterMembershipOptions>(options => options.ExpectedClusterSize = 1);
builder.UseDevelopmentClustering(new IPEndPoint(address, orleansPortSilo));
builder.Configure<ClusterMembershipOptions>(options =>
{
options.ExpectedClusterSize = 1;
});
}
});
@ -88,14 +94,9 @@ namespace Squidex.Config.Orleans
{
["MongoDB"] = () =>
{
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration");
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database");
builder.UseMongoDBReminders(options =>
{
options.ConnectionString = mongoConfiguration;
options.CollectionPrefix = "Orleans_";
options.DatabaseName = mongoDatabaseName;
options.Configure(config);
});
}
});
@ -104,7 +105,17 @@ namespace Squidex.Config.Orleans
return services;
}
public static void Configure(this ClusterOptions options)
private static void Configure(this MongoDBOptions options, IConfiguration config)
{
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration");
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database");
options.ConnectionString = mongoConfiguration;
options.CollectionPrefix = "Orleans_";
options.DatabaseName = mongoDatabaseName;
}
private static void Configure(this ClusterOptions options)
{
options.ClusterId = Constants.OrleansClusterId;
options.ServiceId = Constants.OrleansClusterId;

44
tests/Squidex.Infrastructure.Tests/IPAddressComparerTests.cs

@ -0,0 +1,44 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Linq;
using System.Net;
using Xunit;
namespace Squidex.Infrastructure
{
public class IPAddressComparerTests
{
[Fact]
public void Should_sort_ip_addresses()
{
var source = new[]
{
IPAddress.IPv6Loopback,
IPAddress.Parse("127.0.0.200"),
IPAddress.Parse("127.0.0.255"),
IPAddress.Parse("129.0.0.1"),
IPAddress.Parse("127.0.0.1"),
IPAddress.Parse("127.0.0.200"),
};
var sorted = source.OrderBy(x => x, IPAddressComparer.Instance);
var expected = new[]
{
IPAddress.Parse("127.0.0.1"),
IPAddress.Parse("127.0.0.200"),
IPAddress.Parse("127.0.0.200"),
IPAddress.Parse("127.0.0.255"),
IPAddress.Parse("129.0.0.1"),
IPAddress.IPv6Loopback,
};
Assert.Equal(expected, sorted);
}
}
}
Loading…
Cancel
Save