Skip to content

Instantly share code, notes, and snippets.

@ReubenBond
Created February 26, 2015 20:52
Show Gist options
  • Save ReubenBond/648584a770b615afaf04 to your computer and use it in GitHub Desktop.
Save ReubenBond/648584a770b615afaf04 to your computer and use it in GitHub Desktop.
Orleans: modifying internal provider config
namespace Orleans.Azure.Silos
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reflection;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Orleans.Runtime.Configuration;
using Orleans.Runtime.Host;
/// <summary>
/// The worker role.
/// </summary>
public class WorkerRole : RoleEntryPoint
{
/// <summary>
/// The data connection string key.
/// </summary>
private const string DataConnectionStringKey = "DataConnectionString";
/// <summary>
/// The storage key.
/// </summary>
private const string StorageKey = "Storage";
/// <summary>
/// The orleans azure silo.
/// </summary>
private AzureSilo orleansAzureSilo;
/// <summary>
/// Handle the start event.
/// </summary>
/// <returns>A value indicating whether or not this role started successfully.</returns>
public override bool OnStart()
{
if (!Trace.Listeners.OfType<DiagnosticMonitorTraceListener>().Any() && !RoleEnvironment.IsEmulated)
{
Trace.Listeners.Add(new DiagnosticMonitorTraceListener());
}
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12 * Environment.ProcessorCount;
// For information on handling configuration changes see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
RoleEnvironment.Changing += RoleEnvironmentChanging;
this.orleansAzureSilo = new AzureSilo();
var ok = base.OnStart();
if (ok)
{
var cfg = new ClusterConfiguration();
cfg.LoadFromFile("OrleansConfiguration.xml");
ProviderCategoryConfiguration storageConfiguration;
if (cfg.Globals.ProviderConfigurations.TryGetValue(StorageKey, out storageConfiguration))
{
// Find all storage providers with service configuration key names and modify them as necessary.
foreach (var provider in storageConfiguration.Providers.Where(provider => provider.Value is ProviderConfiguration))
{
string connectionString;
var properties = provider.Value.Properties;
if (properties.TryGetValue(DataConnectionStringKey, out connectionString))
{
ModifyProviderProperty(
provider.Value as ProviderConfiguration,
DataConnectionStringKey,
GetConnectionStringFromServiceConfiguration(connectionString));
}
}
}
// Trace ActivityIds should flow between clients and grains.
cfg.Defaults.PropagateActivityId = true;
// Modify the Azure Liveness ConnectionString as necessary.
cfg.Globals.DataConnectionString = GetConnectionStringFromServiceConfiguration(cfg.Globals.DataConnectionString);
cfg.Globals.DeploymentId = RoleEnvironment.DeploymentId;
ok = this.orleansAzureSilo.Start(RoleEnvironment.DeploymentId, RoleEnvironment.CurrentRoleInstance, cfg);
}
return ok;
}
/// <summary>
/// Run the silo.
/// </summary>
public override void Run()
{
this.orleansAzureSilo.Run(); // Call will block until silo is shutdown
}
/// <summary>
/// Handle the stop event.
/// </summary>
public override void OnStop()
{
this.orleansAzureSilo.Stop();
RoleEnvironment.Changing -= RoleEnvironmentChanging;
base.OnStop();
}
/// <summary>
/// Sets the <paramref name="property"/> property of <paramref name="provider"/> to <paramref name="newValue"/>.
/// </summary>
/// <param name="provider">The provider.</param>
/// <param name="property">The property.</param>
/// <param name="newValue">The new value.</param>
private static void ModifyProviderProperty(ProviderConfiguration provider, string property, string newValue)
{
// Note: This is obviously not a stable solution
var privateProperties = typeof(ProviderConfiguration).GetField("_properties", BindingFlags.NonPublic | BindingFlags.Instance);
if (privateProperties != null)
{
var properties = (Dictionary<string, string>)privateProperties.GetValue(provider);
properties[property] = newValue;
}
}
/// <summary>
/// Returns the connection string stored in service configuration given a connection string.
/// </summary>
/// <param name="originalConnectionString">
/// The original connection string.
/// </param>
/// <returns>
/// The connection string from the service configuration setting indicated by the "ServiceConfigurationSetting"
/// parameter of <paramref name="originalConnectionString"/>, or <paramref name="originalConnectionString"/> if
/// the parameter is unspecified.
/// </returns>
/// <remarks>
/// Returns <see langword="null"/> if the specified parameter does not indicate a valid setting.
/// </remarks>
private static string GetConnectionStringFromServiceConfiguration(string originalConnectionString)
{
// Default string is returned if setting is invalid.
var result = default(string);
var settings = originalConnectionString.Split(';')
.Select(kvp => kvp.Split('='))
.Where(kvp => kvp.Length == 2)
.ToDictionary(kvp => kvp[0], kvp => kvp[1]);
string settingName;
if (settings.TryGetValue("ServiceConfigurationSetting", out settingName))
{
var connectionString = CloudConfigurationManager.GetSetting(settingName);
if (!string.IsNullOrWhiteSpace(connectionString))
{
result = connectionString;
}
}
else
{
// Setting was not provided.
result = originalConnectionString;
}
return result;
}
/// <summary>
/// Handle the RoleEnvironmentChanging event.
/// </summary>
/// <param name="sender">
/// The event sender.
/// </param>
/// <param name="e">
/// The event arguments.
/// </param>
private static void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
{
// If a configuration setting is changing);
if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
{
// Set e.Cancel to true to restart this role instance
e.Cancel = true;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment