Does anyone have any insights to which of the following two pseudo-patterns are the correct way of instantiating/utilizing reliable collections within a stateful service fabric service? Specifically, wondering if one approach is more performant, more memory-consuming or even more error prone.
Approach 1 (get instance from StateManager inside method):
public class MyService : IService {
public async Task<string> GetSomeValueAsync(string input){
var reliableDic = await StateManager.GetOrAddAsync<IReliableDictionary<string, string>>(StateKey);
var result = await reliableDic.TryGetValue(input);
return result.HasValue ? result.Value : null;
}
}
Approach 2 (store collection as member variable on class)
public class MyService : IService {
private bool _isInitialized;
private readonly object _lock = new object();
private IReliableDictionary<string, string> _dictionary;
private async Task Initialize(){
if (_isInitialized){
return;
}
lock(_lock){
if (_isInitialized){
return;
}
_dictionary = await StateManager.GetOrAddAsync<IReliableDictionary<string, string>>(StateKey);
_isInitialized = true;
}
}
public async Task<string> GetSomeValueAsync(string input){
await Initialize();
var result = await _dictionary.TryGetValue(input);
return result.HasValue ? result.Value : null;
}
}
So, approach 1 fetches the dictionary from the StateManager in each method while approach 2 does a lazy initialization check and then uses class members.
Most samples we see are using approach 1, but the idea behind approach 2 is to store the reliable dictionary in an instance field and avoid any StateManager.GetOrAddAsync
hit in each method as well as centralize the handling of the StateKey
which could be beneficial in larger services with many methods and potentially more reliable collections.
Would love to learn if there are any pitfalls or inefficiencies in either approach (obviously approach 2 is more verbose and uses more lines of code, but that is not the primary concern).
Actually there is no real reason to cache result of StateManager.GetOrAddAsync
except saving memory allocations of Task
object or making it available in places where having StateManager
available isn't appropriate.
The reason for this is quite simple - the StateManager
already caches the instance of IRealiableState
for you. So it returns the same instance each time you do StateManager.GetOrAddAsync
(here is the official answer from Microsoft).
You also can check it yourself with the very simple test (the c
is true
):
var q1 = stateManager.GetOrAddAsync<IReliableDictionary<string, string>>("MyDict")
.GetAwaiter().GetResult();
var q2 = stateManager.GetOrAddAsync<IReliableDictionary<string, string>>("MyDict")
.GetAwaiter().GetResult();
var c = q1 == q2;