Skip to content

Instantly share code, notes, and snippets.

@ejsmith
Created April 16, 2023 01:22
Show Gist options
  • Save ejsmith/d8fb84a9b1f07194650b848b95c91bf8 to your computer and use it in GitHub Desktop.
Save ejsmith/d8fb84a9b1f07194650b848b95c91bf8 to your computer and use it in GitHub Desktop.
using Foundatio.Queues;
using System.Collections.Concurrent;
using Microsoft.Extensions.DependencyInjection;
namespace Contacts.Domain.Services;
public interface INamedRegistrationFactory<T> where T : class {
/// <summary>
/// Get instance by name
/// </summary>
/// <param name="name">Instance name</param>
/// <returns>The instance associated with the specified name</returns>
T GetByName(string name);
/// <summary>
/// Get instance by group. Multiple names can belong to a single group / instance.
/// </summary>
/// <param name="group">Group name</param>
/// <returns>The instance associated with the group name</returns>
T GetByGroup(string group);
/// <summary>
/// Get the name of the group by the instance name. Multiple names can belong to a single group.
/// </summary>
/// <param name="name">Instance name</param>
/// <returns>The group name</returns>
string GetGroupName(string name);
/// <summary>
/// The default non-named instance
/// </summary>
T Default { get; }
/// <summary>
/// Get all instances registered in this factory.
/// </summary>
/// <returns>Dictionary of group name and instance</returns>
IDictionary<string, T> GetAll();
}
public interface INamedQueueFactory<T> : INamedRegistrationFactory<IQueue<T>> where T : class { }
public abstract class NamedRegistrationFactory<T> : INamedRegistrationFactory<T> where T : class {
private readonly ConcurrentDictionary<string, T> _instances = new ConcurrentDictionary<string, T>(StringComparer.OrdinalIgnoreCase);
protected readonly IServiceProvider _serviceProvider;
private readonly Dictionary<string, string> _groupToNameMap = new Dictionary<string, string> { { String.Empty, String.Empty } };
public NamedRegistrationFactory(IServiceProvider serviceProvider, string groupToNameMap) {
_serviceProvider = serviceProvider;
if (String.IsNullOrEmpty(groupToNameMap))
return;
ParseGroupToNameMap(groupToNameMap);
}
public T GetByName(string name) {
return GetByGroup(GetGroupName(name));
}
public T Default => GetByGroup(String.Empty);
public T GetByGroup(string group) {
if (group == null)
group = String.Empty;
return _instances.GetOrAdd(group, key => CreateInstance(group));
}
public string GetGroupName(string name) {
string groupName = String.Empty;
if (!String.IsNullOrEmpty(name) && _groupToNameMap.ContainsKey(name))
groupName = _groupToNameMap[name];
return groupName;
}
public IDictionary<string, T> GetAll() {
return _groupToNameMap.Values.Distinct().Select(groupName => new KeyValuePair<string, T>(groupName, GetByGroup(groupName))).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
protected abstract T CreateInstance(string groupName);
private void ParseGroupToNameMap(string connectionString) {
var groups = connectionString.Split(';')
.Where(kvp => kvp.Contains('='))
.Select(kvp => kvp.Split(new[] { '=' }, 2))
.ToDictionary(kvp => kvp[0].Trim(), kvp => kvp[1].Trim(), StringComparer.InvariantCultureIgnoreCase);
foreach (var group in groups) {
string[] keys = group.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var key in keys)
_groupToNameMap.Add(key, group.Key);
}
}
}
public class InMemoryNamedQueueFactory<T> : NamedRegistrationFactory<IQueue<T>>, INamedQueueFactory<T> where T : class {
public InMemoryNamedQueueFactory(IServiceProvider serviceProvider, string queueNamesConfig) : base(serviceProvider, queueNamesConfig) { }
protected override IQueue<T> CreateInstance(string groupName) {
var behaviors = _serviceProvider.GetServices<IQueueBehavior<T>>().ToList();
return new InMemoryQueue<T>(new InMemoryQueueOptions<T> {
Behaviors = behaviors,
WorkItemTimeout = TimeSpan.FromHours(1)
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment