Created
July 6, 2015 12:29
-
-
Save ReubenBond/f7d7dd546e83a8a8856e to your computer and use it in GitHub Desktop.
Orleans with client/server/interfaces/implementations in a single file. https://github.com/dotnet/orleans/pull/528
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace RosleansSilo | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net; | |
using System.Net.Sockets; | |
using System.Threading.Tasks; | |
using Orleans; | |
using Orleans.Providers; | |
using Orleans.Runtime.Configuration; | |
using Orleans.Runtime.Host; | |
using Orleans.Storage; | |
public interface IHappyGrain : IGrainWithGuidKey | |
{ | |
Task<MyCustomClass> ReadMindUsingTelepathy(string wordsOfWisdom); | |
} | |
[StorageProvider(ProviderName = "default")] | |
public class HappyGrain : Grain<MyCustomClass>, IHappyGrain | |
{ | |
public Task<MyCustomClass> ReadMindUsingTelepathy(string wordsOfWisdom) | |
{ | |
if (this.State.Messages == null) | |
{ | |
this.State.Messages = new List<string>(); | |
} | |
// This is just random silliness :) | |
this.State.Messages.Reverse(); | |
this.State.Messages.Add(wordsOfWisdom); | |
this.State.Messages.Reverse(); | |
if (this.State.Messages.Count > 5) | |
{ | |
this.State.Messages.RemoveRange(5, this.State.Messages.Count - 5); | |
} | |
this.State.Count = this.State.Messages.Count; | |
return Task.FromResult(this.State); | |
} | |
} | |
public class MyCustomClass : GrainState | |
{ | |
public int Count { get; set; } | |
public List<string> Messages { get; set; } | |
public override string ToString() | |
{ | |
var messages = this.Messages ?? Enumerable.Empty<string>(); | |
return string.Format( | |
"Count: {0}, Messages:\n{1}", | |
this.Count, | |
string.Join("\n", messages.Select((_, i) => string.Format("[{0}] {1}", i, _)))); | |
} | |
} | |
internal class Program | |
{ | |
private const string DataConnectionString = "UseDevelopmentStorage=true"; | |
private const string DeploymentId = "blah"; | |
private static readonly Random Random = new Random(); | |
private static void Main(string[] args) | |
{ | |
if (args.Length == 0 || args[0] == "s") | |
{ | |
var hostConfig = GetClusterConfiguration(); | |
// Start the silo. | |
var instanceId = Guid.NewGuid().ToString("N").Substring(0, 5); | |
var silo = new SiloHost(instanceId, hostConfig); | |
silo.InitializeOrleansSilo(); | |
if (!silo.StartOrleansSilo()) | |
{ | |
Console.WriteLine("Failed to start silo"); | |
} | |
} | |
else | |
{ | |
// Configure the client | |
GrainClient.Initialize( | |
new ClientConfiguration | |
{ | |
DeploymentId = DeploymentId, | |
DataConnectionString = DataConnectionString, | |
GatewayProvider = ClientConfiguration.GatewayProviderType.AzureTable, | |
}); | |
// Mess around with a grain. | |
var grain = GrainClient.GrainFactory.GetGrain<IHappyGrain>(Guid.Empty); | |
for (int i = 0; i < 5; i++) | |
{ | |
var result = grain.ReadMindUsingTelepathy(Random.Next() + " trust in yourself").Result; | |
Console.WriteLine(result); | |
} | |
} | |
Console.ReadKey(); | |
} | |
#region Helpers | |
private static ClusterConfiguration GetClusterConfiguration() | |
{ | |
// Work out network details such as a suitable listen address and ports. | |
var hostAddress = GetNodeAddress().Result; | |
var internalPort = Random.Next(50000, ushort.MaxValue - 1); | |
var proxyPort = Random.Next(30000, 49999); | |
// Configure the host to use the local Azure Storage Emulator for service discovery. | |
var hostConfig = new ClusterConfiguration | |
{ | |
Defaults = | |
{ | |
HostNameOrIPAddress = hostAddress.ToString(), | |
Port = internalPort, | |
ProxyGatewayEndpoint = new IPEndPoint(hostAddress, proxyPort), | |
}, | |
Globals = | |
{ | |
DeploymentId = DeploymentId, | |
ServiceId = Guid.NewGuid(), | |
DataConnectionString = DataConnectionString, | |
LivenessType = GlobalConfiguration.LivenessProviderType.AzureTable, | |
ReminderServiceType = GlobalConfiguration.ReminderServiceProviderType.AzureTable, | |
} | |
}; | |
hostConfig.Globals.RegisterStorageProvider<MemoryStorage>("default"); | |
return hostConfig; | |
} | |
public static async Task<IPAddress> GetNodeAddress(string host = null) | |
{ | |
var nodeAddresses = await Dns.GetHostAddressesAsync(host ?? Dns.GetHostName()); | |
var nodeAddressV4 = | |
nodeAddresses.FirstOrDefault(_ => _.AddressFamily == AddressFamily.InterNetwork && !IsLocalAddress(_)); | |
var nodeAddressV6 = | |
nodeAddresses.FirstOrDefault(_ => _.AddressFamily == AddressFamily.InterNetworkV6 && !IsLocalAddress(_)); | |
var nodeAddress = nodeAddressV4 ?? nodeAddressV6; | |
if (nodeAddress == null) | |
{ | |
throw new InvalidOperationException("Could not determine network address."); | |
} | |
return nodeAddress; | |
} | |
public static bool IsLocalAddress(IPAddress address) | |
{ | |
if (address.AddressFamily == AddressFamily.InterNetworkV6) | |
{ | |
return address.IsIPv6LinkLocal; | |
} | |
// 169.254.0.0/16 | |
var addrBytes = address.GetAddressBytes(); | |
return addrBytes[0] == 0xA9 && addrBytes[1] == 0xFE; | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment