Skip to content

Commit b1dcdc0

Browse files
sergeybykovReubenBond
authored andcommitted
#2459: Grain Services by @jamescarter-le (#2531)
* Implement Grain Services which are a partitioned SystemTarget service. Can invoke a Grain Service with a test. Added Grain Service Configuration Tests reporting: Exception thrown: 'Orleans.CodeGenerator.CodeGenerationException' in OrleansCodeGenerator.dll Additional information: (1,18913): error CS0122: 'ITestHooksSystemTarget' is inaccessible due to its protection level Resolved GrainService GrainId, InsideRuntimeClient using ReminderRegistr SystemTarget public, GrainServiceClient used SystemTarget is now public, removed GrainService analog, now contains just GrainService logic GrainServiceClient is used to locate the IReminderService Cannot capture the correct Reminder GrainId (GrainClassData not available)? SystemTarget public, GrainServiceClient used Initial stab at implementing a partitioned system service. From @sergeybykov comments, attempted the below: --- I see at least two potential ways, likely complementary, to expose such functionality to application code. 1) Partitioned system service. Essentially a generalized version of the Reminder service, but with an application system target class instead of LocalReminderService, e.g. GrainService, and a corresponding equivalent to ReminderRegistry proxy class, e.g. GrainServiceClient. We only create a single LocalReminderService system target per silo today, but it shouldn't be too difficult to make that number configurable. In this approach, callers are completely oblivious to partitioning and routing, and it's the responsibility of the GrainService to react to repartitioning events and changes to the ring range it owns. * Added an explicit method NewGrainServiceKey to UniqueKey instead of reusing the more general NewKey directly. * Added type name to log statements and as the logger name. * Reverted RegisterSystemTarget back to internal. * Eliminated a warning about deprecated Consul method. * Added XML commenst and tweaked a few methods to eliminate build warnings. * Tweaks to make code .NET Core compatible. * Support dependency injection in GrainServices (#6)
1 parent ae01368 commit b1dcdc0

33 files changed

+735
-209
lines changed

src/Orleans/Configuration/GlobalConfiguration.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,11 @@ internal void SetReminderServiceType(ReminderServiceProviderType reminderType)
412412
/// </summary>
413413
public IDictionary<string, ProviderCategoryConfiguration> ProviderConfigurations { get; set; }
414414

415+
/// <summary>
416+
/// Configuration for grain services.
417+
/// </summary>
418+
public GrainServiceConfigurations GrainServiceConfigurations { get; set; }
419+
415420
/// <summary>
416421
/// The time span between when we have added an entry for an activation to the grain directory and when we are allowed
417422
/// to conditionally remove that entry.
@@ -568,6 +573,7 @@ internal GlobalConfiguration()
568573
MockReminderTableTimeout = DEFAULT_MOCK_REMINDER_TABLE_TIMEOUT;
569574

570575
ProviderConfigurations = new Dictionary<string, ProviderCategoryConfiguration>();
576+
GrainServiceConfigurations = new GrainServiceConfigurations();
571577
}
572578

573579
public override string ToString()
@@ -976,6 +982,11 @@ internal override void Load(XmlElement root)
976982
break;
977983

978984
default:
985+
if (child.LocalName.Equals("GrainServices", StringComparison.Ordinal))
986+
{
987+
GrainServiceConfigurations = GrainServiceConfigurations.Load(child);
988+
}
989+
979990
if (child.LocalName.EndsWith("Providers", StringComparison.Ordinal))
980991
{
981992
var providerCategory = ProviderCategoryConfiguration.Load(child);
@@ -1101,6 +1112,11 @@ public bool TryGetProviderConfiguration(string providerTypeFullName, string prov
11011112
public IEnumerable<IProviderConfiguration> GetAllProviderConfigurations()
11021113
{
11031114
return ProviderConfigurationUtility.GetAllProviderConfigurations(ProviderConfigurations);
1104-
}
1115+
}
1116+
1117+
public void RegisterGrainService(string serviceName, string clientType, string serviceType, IDictionary<string, string> properties = null)
1118+
{
1119+
GrainServiceConfigurationsUtility.RegisterGrainService(GrainServiceConfigurations, serviceName, clientType, serviceType, properties);
1120+
}
11051121
}
11061122
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Xml;
4+
5+
namespace Orleans.Runtime.Configuration
6+
{
7+
[Serializable]
8+
public class GrainServiceConfigurations
9+
{
10+
public IDictionary<string, IGrainServiceConfiguration> GrainServices { get; set; }
11+
12+
public GrainServiceConfigurations()
13+
{
14+
GrainServices = new Dictionary<string, IGrainServiceConfiguration>();
15+
}
16+
17+
internal static GrainServiceConfigurations Load(XmlElement child)
18+
{
19+
var container = new GrainServiceConfigurations();
20+
21+
var nsManager = new XmlNamespaceManager(new NameTable());
22+
nsManager.AddNamespace("orleans", "urn:orleans");
23+
24+
GrainServiceConfiguration.LoadProviderConfigurations(
25+
child, nsManager, container.GrainServices,
26+
c => container.GrainServices.Add(c.Name, c));
27+
28+
return container;
29+
}
30+
}
31+
32+
internal static class GrainServiceConfigurationsUtility
33+
{
34+
internal static void RegisterGrainService(GrainServiceConfigurations grainServicesConfig, string serviceName, string clientType, string serviceType, IDictionary<string, string> properties = null)
35+
{
36+
if (grainServicesConfig.GrainServices.ContainsKey(serviceName))
37+
throw new InvalidOperationException(
38+
string.Format("Grain service of with name '{0}' has been already registered", serviceName));
39+
40+
var config = new GrainServiceConfiguration(
41+
properties ?? new Dictionary<string, string>(),
42+
serviceName, clientType, serviceType);
43+
44+
grainServicesConfig.GrainServices.Add(config.Name, config);
45+
}
46+
}
47+
48+
public interface IGrainServiceConfiguration
49+
{
50+
string Name { get; set; }
51+
string ClientType { get; set; }
52+
string ServiceType { get; set; }
53+
}
54+
55+
[Serializable]
56+
public class GrainServiceConfiguration : IGrainServiceConfiguration
57+
{
58+
private IDictionary<string, string> properties;
59+
60+
public string Name { get; set; }
61+
public string ClientType { get; set; }
62+
public string ServiceType { get; set; }
63+
64+
public GrainServiceConfiguration() {}
65+
66+
public GrainServiceConfiguration(IDictionary<string, string> properties, string serviceName, string clientType, string serviceType)
67+
{
68+
this.properties = properties;
69+
Name = serviceName;
70+
ClientType = clientType;
71+
ServiceType = serviceType;
72+
}
73+
74+
internal void Load(XmlElement child, IDictionary<string, IGrainServiceConfiguration> alreadyLoaded, XmlNamespaceManager nsManager)
75+
{
76+
if (nsManager == null)
77+
{
78+
nsManager = new XmlNamespaceManager(new NameTable());
79+
nsManager.AddNamespace("orleans", "urn:orleans");
80+
}
81+
82+
if (child.HasAttribute("Name"))
83+
{
84+
Name = child.GetAttribute("Name");
85+
}
86+
87+
if (alreadyLoaded != null && alreadyLoaded.ContainsKey(Name))
88+
{
89+
return;
90+
}
91+
92+
if (child.HasAttribute("ClientType"))
93+
{
94+
ClientType = child.GetAttribute("ClientType");
95+
}
96+
else
97+
{
98+
throw new FormatException("Missing 'ClientType' attribute on 'GrainService' element");
99+
}
100+
101+
if (child.HasAttribute("ServiceType"))
102+
{
103+
ServiceType = child.GetAttribute("ServiceType");
104+
}
105+
else
106+
{
107+
throw new FormatException("Missing 'ServiceType' attribute on 'GrainService' element");
108+
}
109+
110+
if (String.IsNullOrEmpty(Name))
111+
{
112+
Name = ServiceType;
113+
}
114+
115+
properties = new Dictionary<string, string>();
116+
for (int i = 0; i < child.Attributes.Count; i++)
117+
{
118+
var key = child.Attributes[i].LocalName;
119+
var val = child.Attributes[i].Value;
120+
if ((key != "Type") && (key != "Name"))
121+
{
122+
properties[key] = val;
123+
}
124+
}
125+
}
126+
127+
internal static void LoadProviderConfigurations(XmlElement root, XmlNamespaceManager nsManager,
128+
IDictionary<string, IGrainServiceConfiguration> alreadyLoaded, Action<IGrainServiceConfiguration> add)
129+
{
130+
var nodes = root.SelectNodes("orleans:GrainService", nsManager);
131+
foreach (var node in nodes)
132+
{
133+
var subElement = node as XmlElement;
134+
if (subElement == null) continue;
135+
136+
var config = new GrainServiceConfiguration();
137+
config.Load(subElement, alreadyLoaded, nsManager);
138+
add(config);
139+
}
140+
}
141+
}
142+
}

src/Orleans/IDs/GrainId.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Globalization;
3+
using System.Reflection;
4+
using System.Runtime.CompilerServices;
35
using Orleans.Core;
46
using Orleans.Serialization;
57

@@ -90,6 +92,11 @@ internal static GrainId GetGrainId(long typeCode, string primaryKey)
9092
typeCode, primaryKey));
9193
}
9294

95+
internal static GrainId GetGrainServiceGrainId(short id, int typeData)
96+
{
97+
return FindOrCreateGrainId(UniqueKey.NewGrainServiceKey(id, typeData));
98+
}
99+
93100
public Guid PrimaryKey
94101
{
95102
get { return GetPrimaryKey(); }

src/Orleans/IDs/UniqueKey.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ public static UniqueKey NewSystemTargetKey(short systemId)
161161
return NewKey(0, n1, Category.SystemTarget, 0, null);
162162
}
163163

164+
public static UniqueKey NewGrainServiceKey(short key, long typeData)
165+
{
166+
ulong n1 = unchecked((ulong)key);
167+
return NewKey(0, n1, Category.SystemTarget, typeData, null);
168+
}
169+
164170
internal static UniqueKey NewKey(ulong n0, ulong n1, ulong typeCodeData, string keyExt)
165171
{
166172
ValidateKeyExt(keyExt, typeCodeData);

src/Orleans/Orleans.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
<Compile Include="Async\UnobservedExceptionsHandlerClass.cs" />
7979
<Compile Include="Async\TaskExtensions.cs" />
8080
<Compile Include="CodeGeneration\GeneratedAssembly.cs" />
81+
<Compile Include="Configuration\GrainServiceConfiguration.cs" />
8182
<Compile Include="Core\GrainCasterFactory.cs" />
8283
<Compile Include="Core\IInternalGrainFactory.cs" />
8384
<Compile Include="Logging\LoggerExtensions.cs" />
@@ -144,6 +145,8 @@
144145
<Compile Include="Serialization\ILDelegateBuilder.cs" />
145146
<Compile Include="Serialization\OrleansJsonSerializer.cs" />
146147
<Compile Include="Serialization\BinaryFormatterSerializer.cs" />
148+
<Compile Include="Services\IGrainServiceClient.cs" />
149+
<Compile Include="Services\IGrainService.cs" />
147150
<Compile Include="Utils\ReferenceEqualsComparer.cs" />
148151
<Compile Include="Serialization\ReflectedSerializationMethodInfo.cs" />
149152
<Compile Include="Serialization\SerializationTestEnvironment.cs" />
@@ -259,7 +262,6 @@
259262
<Compile Include="Streams\Core\StreamSequenceToken.cs" />
260263
<Compile Include="Streams\Core\StreamSubscriptionHandle.cs" />
261264
<Compile Include="Timers\AsyncTaskSafeTimer.cs" />
262-
<Compile Include="Timers\ReminderRegistry.cs" />
263265
<Compile Include="Timers\TimerRegistry.cs" />
264266
<Compile Include="Utils\SetExtensions.cs" />
265267
<Compile Include="Placement\ActivationCountBasedPlacement.cs" />

src/Orleans/Runtime/Constants.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ internal class Constants
3434
public static readonly GrainId ClientObserverRegistrarId = GrainId.GetSystemTargetGrainId(13);
3535
public static readonly GrainId CatalogId = GrainId.GetSystemTargetGrainId(14);
3636
public static readonly GrainId MembershipOracleId = GrainId.GetSystemTargetGrainId(15);
37-
public static readonly GrainId ReminderServiceId = GrainId.GetSystemTargetGrainId(16);
3837
public static readonly GrainId TypeManagerId = GrainId.GetSystemTargetGrainId(17);
3938
public static readonly GrainId ProviderManagerSystemTargetId = GrainId.GetSystemTargetGrainId(19);
4039
public static readonly GrainId DeploymentLoadPublisherSystemTargetId = GrainId.GetSystemTargetGrainId(22);
@@ -82,7 +81,6 @@ internal class Constants
8281
{CatalogId,"Catalog"},
8382
{MembershipOracleId,"MembershipOracle"},
8483
{MultiClusterOracleId,"MultiClusterOracle"},
85-
{ReminderServiceId,"ReminderService"},
8684
{TypeManagerId,"TypeManagerId"},
8785
{ProviderManagerSystemTargetId, "ProviderManagerSystemTarget"},
8886
{DeploymentLoadPublisherSystemTargetId, "DeploymentLoadPublisherSystemTarget"},
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace Orleans.Services
2+
{
3+
public interface IGrainService : ISystemTarget
4+
{
5+
}
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace Orleans.Services
2+
{
3+
public interface IGrainServiceClient<TGrainService> where TGrainService : IGrainService
4+
{
5+
}
6+
}

src/Orleans/SystemTargetInterfaces/IReminderService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
using System.Collections.Generic;
33
using System.Threading.Tasks;
44
using Orleans.Runtime;
5-
5+
using Orleans.Services;
66

77
namespace Orleans
88
{
9-
internal interface IReminderService : ISystemTarget
9+
public interface IReminderService : IGrainService
1010
{
1111
Task Start();
1212
Task Stop();

src/Orleans/SystemTargetInterfaces/ISystemTarget.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Orleans
1010
/// Proxy class is being generated for ISystemTarget, just like for IGrain
1111
/// System target are scheduled by the runtime scheduler and follow turn based concurrency.
1212
/// </summary>
13-
internal interface ISystemTarget : IAddressable
13+
public interface ISystemTarget : IAddressable
1414
{
1515
}
1616

0 commit comments

Comments
 (0)