Skip to content

Commit

Permalink
Add INameResolver integration for SingletonAttribute
Browse files Browse the repository at this point in the history
  • Loading branch information
mathewc committed Oct 7, 2015
1 parent 5f11290 commit 1b9c21e
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public static async Task<JobHostContext> CreateAndLogHostStartedAsync(
if (singletonManager == null)
{
IStorageAccount storageAccount = await storageAccountProvider.GetStorageAccountAsync(cancellationToken);
singletonManager = new SingletonManager(storageAccount.CreateBlobClient(), backgroundExceptionDispatcher, config.Singleton, trace);
singletonManager = new SingletonManager(storageAccount.CreateBlobClient(), backgroundExceptionDispatcher, config.Singleton, trace, config.NameResolver);
}

using (CancellationTokenSource combinedCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, shutdownToken))
Expand Down
11 changes: 9 additions & 2 deletions src/Microsoft.Azure.WebJobs.Host/Singleton/SingletonManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace Microsoft.Azure.WebJobs.Host
internal class SingletonManager
{
internal const string FunctionInstanceMetadataKey = "FunctionInstance";
private readonly INameResolver _nameResolver;
private readonly IBackgroundExceptionDispatcher _backgroundExceptionDispatcher;
private readonly SingletonConfiguration _config;
private IStorageBlobDirectory _directory;
Expand All @@ -36,8 +37,9 @@ internal SingletonManager()
{
}

public SingletonManager(IStorageBlobClient blobClient, IBackgroundExceptionDispatcher backgroundExceptionDispatcher, SingletonConfiguration config, TraceWriter trace)
public SingletonManager(IStorageBlobClient blobClient, IBackgroundExceptionDispatcher backgroundExceptionDispatcher, SingletonConfiguration config, TraceWriter trace, INameResolver nameResolver = null)
{
_nameResolver = nameResolver;
_backgroundExceptionDispatcher = backgroundExceptionDispatcher;
_directory = blobClient.GetContainerReference(HostContainerNames.Hosts)
.GetDirectoryReference(HostDirectoryNames.SingletonLocks);
Expand Down Expand Up @@ -157,8 +159,13 @@ public static string FormatLockId(MethodInfo method, string scope)
return lockId;
}

public static string GetBoundScope(string scope, IReadOnlyDictionary<string, object> bindingData)
public string GetBoundScope(string scope, IReadOnlyDictionary<string, object> bindingData)
{
if (_nameResolver != null)
{
scope = _nameResolver.ResolveWholeString(scope);
}

if (bindingData != null)
{
BindingTemplate bindingTemplate = BindingTemplate.FromString(scope);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private async Task<IReadOnlyDictionary<string, IValueProvider>> BindCoreAsync(Va
SingletonAttribute singletonAttribute = _descriptor.Method.GetCustomAttribute<SingletonAttribute>();
if (singletonAttribute != null)
{
string boundScope = SingletonManager.GetBoundScope(singletonAttribute.Scope, bindingData);
string boundScope = _singletonManager.GetBoundScope(singletonAttribute.Scope, bindingData);
IValueProvider singletonValueProvider = new SingletonValueProvider(_descriptor.Method, boundScope, context.FunctionInstanceId.ToString(), singletonAttribute, _singletonManager);
valueProviders.Add(SingletonValueProvider.SingletonParameterName, singletonValueProvider);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class SingletonManagerTests
private Mock<IStorageBlockBlob> _mockStorageBlob;
private TestTraceWriter _trace = new TestTraceWriter(TraceLevel.Verbose);
private Dictionary<string, string> _mockBlobMetadata;
private TestNameResolver _nameResolver;

public SingletonManagerTests()
{
Expand All @@ -52,7 +53,8 @@ public SingletonManagerTests()
TestHelpers.SetField(_singletonConfig, "_lockPeriod", TimeSpan.FromMilliseconds(500));
_singletonConfig.LockAcquisitionTimeout = TimeSpan.FromMilliseconds(200);

_singletonManager = new SingletonManager(mockBlobClient.Object, _mockExceptionDispatcher.Object, _singletonConfig, _trace);
_nameResolver = new TestNameResolver();
_singletonManager = new SingletonManager(mockBlobClient.Object, _mockExceptionDispatcher.Object, _singletonConfig, _trace, _nameResolver);

_singletonManager.MinimumLeaseRenewalInterval = TimeSpan.FromMilliseconds(250);
}
Expand Down Expand Up @@ -240,7 +242,7 @@ public void GetBoundScope_Success_ReturnsExceptedResult()
bindingData.Add("Region", "testregion");
bindingData.Add("Zone", 1);

string result = SingletonManager.GetBoundScope(@"{Region}\{Zone}", bindingData);
string result = _singletonManager.GetBoundScope(@"{Region}\{Zone}", bindingData);

Assert.Equal(@"testregion\1", result);
}
Expand All @@ -252,7 +254,7 @@ public void GetBoundScope_BindingError_Throws()
Dictionary<string, object> bindingData = new Dictionary<string, object>();
bindingData.Add("Region", "testregion");

InvalidOperationException exception = Assert.Throws<InvalidOperationException>(() => SingletonManager.GetBoundScope(@"{Region}\{Zone}", bindingData));
InvalidOperationException exception = Assert.Throws<InvalidOperationException>(() => _singletonManager.GetBoundScope(@"{Region}\{Zone}", bindingData));

Assert.Equal("No value for named parameter 'Zone'.", exception.Message);
}
Expand All @@ -262,7 +264,7 @@ public void GetBoundScope_BindingError_Throws()
[InlineData("scope", "scope")]
public void GetBoundScope_NullBindingDataScenarios_Succeeds(string scope, string expectedResult)
{
string result = SingletonManager.GetBoundScope(scope, null);
string result = _singletonManager.GetBoundScope(scope, null);
Assert.Equal(expectedResult, result);
}

Expand All @@ -271,18 +273,43 @@ public void GetBoundScope_NullBindingDataScenarios_Succeeds(string scope, string
[InlineData("scope", "scope")]
[InlineData("scope{P1}", "scopeTest1")]
[InlineData("scope:{P1}-{P2}", "scope:Test1-Test2")]
[InlineData("%var1%", "Value1")]
[InlineData("{P1}%var2%{P2}%var1%", "Test1Value2Test2Value1")]
public void GetBoundScope_BindingDataScenarios_Succeeds(string scope, string expectedResult)
{
Dictionary<string, object> bindingData = new Dictionary<string, object>();
bindingData.Add("P1", "Test1");
bindingData.Add("P2", "Test2");

string result = SingletonManager.GetBoundScope(scope, bindingData);
_nameResolver.Names.Add("var1", "Value1");
_nameResolver.Names.Add("var2", "Value2");

string result = _singletonManager.GetBoundScope(scope, bindingData);
Assert.Equal(expectedResult, result);
}

private static void TestJob()
{
}

private class TestNameResolver : INameResolver
{
public TestNameResolver()
{
Names = new Dictionary<string, string>();
}

public Dictionary<string, string> Names { get; private set; }

public string Resolve(string name)
{
string value = null;
if (Names.TryGetValue(name, out value))
{
return value;
}
throw new NotImplementedException();
}
}
}
}

0 comments on commit 1b9c21e

Please sign in to comment.