Skip to content

Instantly share code, notes, and snippets.

@rikbosch
Last active November 3, 2017 09:35
Show Gist options
  • Save rikbosch/508661d423ac4228c1ac5a4a4c7f28f8 to your computer and use it in GitHub Desktop.
Save rikbosch/508661d423ac4228c1ac5a4a4c7f28f8 to your computer and use it in GitHub Desktop.
OrleansCommunicationListener 2.0.0-beta1
internal class OrleansSiloHostCommunicationListener : ICommunicationListener
{
private readonly ISiloHost _host;
public OrleansSiloHostCommunicationListener(StatelessService service, Action<ISiloHostBuilder> app)
{
var builder = new SiloHostBuilder();
//configure
app(builder);
//add SF
builder.AddServiceFabric(service);
_host = builder.Build();
}
public async Task<string> OpenAsync(CancellationToken cancellationToken)
{
await _host.StartAsync(cancellationToken);
// mimic default orleans service fabric communicationlistener
var nodeConfig = _host.Services.GetRequiredService<NodeConfiguration>();
return JsonConvert.SerializeObject(new FabricSiloInfo(nodeConfig));
}
public Task CloseAsync(CancellationToken cancellationToken)
{
return _host.StopAsync(cancellationToken);
}
public void Abort()
{
_host.Services.GetRequiredService<Silo>().Stop();
}
}
public static class SerivceFabricSiloHostBuilderExtensions
{
/// <summary>
/// Add servicefabric support to silohost builder
/// Use last of chain
/// </summary>
/// <param name="builder"></param>
/// <param name="service"></param>
/// <returns></returns>
public static ISiloHostBuilder AddServiceFabric(this ISiloHostBuilder builder, StatelessService service)
{
//SF specific
builder.ConfigureServices(x =>
{
x.AddServiceFabricSupport(service);
x.AddSingleton(service.Context);
x.Decorate<ClusterConfiguration>((config, provider) =>
{
AdaptForServiceFabric(config, provider.GetRequiredService<StatelessServiceContext>());
return config;
});
x.Configure<SiloIdentityOptions>(options =>
{
options.SiloName = GetDefaultSiloName(service);
});
});
return builder;
}
private static string GetDefaultSiloName(StatelessService service)
{
return Regex.Replace(service.Context.ServiceName.PathAndQuery.Trim('/'), "[^a-zA-Z0-9_]", "_") + "_" +
service.Context.ReplicaOrInstanceId.ToString("X");
}
/// <summary>
/// The name used to identify the silo-to-silo communication endpoint.
/// </summary>
public const string SiloEndpointName = "OrleansSiloEndpoint";
/// <summary>
/// The name used to identify the client-to-silo communication endpoint.
/// </summary>
public const string GatewayEndpointName = "OrleansProxyEndpoint";
static void AdaptForServiceFabric(ClusterConfiguration config, StatelessServiceContext context)
{
var activation = context.CodePackageActivationContext;
var endpoints = activation.GetEndpoints();
var siloEndpoint = GetEndpoint(endpoints, SiloEndpointName);
var gatewayEndpoint = GetEndpoint(endpoints, GatewayEndpointName);
if (string.IsNullOrWhiteSpace(config.Defaults.HostNameOrIPAddress))
{
config.Defaults.HostNameOrIPAddress = context.NodeContext.IPAddressOrFQDN;
}
config.Defaults.Port = siloEndpoint.Port;
config.Defaults.ProxyGatewayEndpoint = new IPEndPoint(config.Defaults.Endpoint.Address, gatewayEndpoint.Port);
if (config.Defaults.Generation == 0)
{
config.Defaults.Generation = SiloAddress.AllocateNewGeneration();
}
}
static EndpointResourceDescription GetEndpoint(
KeyedCollection<string, EndpointResourceDescription> endpoints,
string endpointName)
{
if (!endpoints.Contains(endpointName))
{
throw new KeyNotFoundException(
$"Endpoint \"{endpointName}\" not found in service manifest. Ensure the service has a TCP endpoint with that name.");
}
return endpoints[endpointName];
}
}
public static class ServiceCollectionExtensions
{
public static IServiceCollection Decorate<TService>(this IServiceCollection services, Func<TService, IServiceProvider, TService> decorator)
{
var descriptors = services.GetDescriptors<TService>();
foreach (var descriptor in descriptors)
{
services.Replace(descriptor.Decorate(decorator));
}
return services;
}
public static IServiceCollection Decorate<TService>(this IServiceCollection services, Func<TService, TService> decorator)
{
var descriptors = services.GetDescriptors<TService>();
foreach (var descriptor in descriptors)
{
services.Replace(descriptor.Decorate(decorator));
}
return services;
}
private static List<ServiceDescriptor> GetDescriptors<TService>(this IServiceCollection services)
{
var descriptors = new List<ServiceDescriptor>();
foreach (var service in services)
{
if (service.ServiceType == typeof(TService))
{
descriptors.Add(service);
}
}
if (descriptors.Count == 0)
{
throw new InvalidOperationException($"Could not find any registered services for type '{typeof(TService).FullName}'.");
}
return descriptors;
}
private static ServiceDescriptor Decorate<TService>(this ServiceDescriptor descriptor, Func<TService, IServiceProvider, TService> decorator)
{
return descriptor.WithFactory(provider => decorator((TService)descriptor.GetInstance(provider), provider));
}
private static ServiceDescriptor Decorate<TService>(this ServiceDescriptor descriptor, Func<TService, TService> decorator)
{
return descriptor.WithFactory(provider => decorator((TService)descriptor.GetInstance(provider)));
}
private static ServiceDescriptor WithFactory(this ServiceDescriptor descriptor, Func<IServiceProvider, object> factory)
{
return ServiceDescriptor.Describe(descriptor.ServiceType, factory, descriptor.Lifetime);
}
private static object GetInstance(this ServiceDescriptor descriptor, IServiceProvider provider)
{
if (descriptor.ImplementationInstance != null)
{
return descriptor.ImplementationInstance;
}
if (descriptor.ImplementationType != null)
{
return provider.GetServiceOrCreateInstance(descriptor.ImplementationType);
}
return descriptor.ImplementationFactory(provider);
}
private static object GetServiceOrCreateInstance(this IServiceProvider provider, Type type)
{
return ActivatorUtilities.GetServiceOrCreateInstance(provider, type);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment