Skip to content

Instantly share code, notes, and snippets.

@ramonsmits
Last active June 3, 2019 20:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ramonsmits/4d893c41cb6de4dd4acd95d434d83a73 to your computer and use it in GitHub Desktop.
Save ramonsmits/4d893c41cb6de4dd4acd95d434d83a73 to your computer and use it in GitHub Desktop.
NServiceBus in memory least recently used gateway deduplication
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Runtime.CompilerServices;
using NServiceBus;
using NServiceBus.Features;
using NServiceBus.Gateway.Deduplication;
using NServiceBus.Persistence;
/// <remarks>All collection operations are O(1)</remarks>
class InMemoryLRUGatewayDeduplication : IDeduplicateMessages
{
public InMemoryLRUGatewayDeduplication()
{
if (!int.TryParse(ConfigurationManager.AppSettings[MaxSizeKey], out MaxSize))
{
MaxSize = MaxSizeDefault;
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
public bool DeduplicateMessage(string clientId, DateTime timeReceived)
{
// Return FALSE if item EXISTS, TRUE if ADDED
if (set.TryGetValue(clientId, out var existingNode)) // O(1)
{
list.Remove(existingNode); // O(1) operation, because we got the node reference
list.AddLast(clientId); // O(1) operation
return false;
}
else
{
if (set.Count == MaxSize)
{
var id = list.First.Value;
set.Remove(id); // O(1)
list.RemoveFirst(); // O(1)
}
var node = list.AddLast(clientId); // O(1)
set.Add(clientId, node); // O(1)
return true;
}
}
const string MaxSizeKey = "NServiceBus/InMemoryLRUGatewayDeduplication/MaxSize";
const int MaxSizeDefault = 1000;
readonly int MaxSize;
readonly LinkedList<string> list = new LinkedList<string>();
readonly Dictionary<string, LinkedListNode<string>> set = new Dictionary<string, LinkedListNode<string>>();
}
class InMemoryLRUGatewayDeduplicationPersistence : PersistenceDefinition
{
internal InMemoryLRUGatewayDeduplicationPersistence()
{
Supports<StorageType.GatewayDeduplication>(s => s.EnableFeatureByDefault<InMemoryLRUGatewayPersistence>());
}
}
class InMemoryLRUGatewayPersistence : Feature
{
internal InMemoryLRUGatewayPersistence()
{
DependsOn("Gateway");
}
/// <summary>
/// See <see cref="Feature.Setup"/>
/// </summary>
protected override void Setup(FeatureConfigurationContext context)
{
context.Container.ConfigureComponent<InMemoryLRUGatewayDeduplication>(DependencyLifecycle.SingleInstance);
}
}
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using NServiceBus;
using NServiceBus.Extensibility;
using NServiceBus.Features;
using NServiceBus.Gateway.Deduplication;
using NServiceBus.Persistence;
/// <remarks>All collection operations are O(1)</remarks>
class InMemoryLRUGatewayDeduplication : IDeduplicateMessages
{
public InMemoryLRUGatewayDeduplication()
{
if (!int.TryParse(ConfigurationManager.AppSettings[MaxSizeKey], out MaxSize))
{
MaxSize = MaxSizeDefault;
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
public Task<bool> DeduplicateMessage(string clientId, DateTime timeReceived, ContextBag context)
{
// Return FALSE if item EXISTS, TRUE if ADDED
if (set.TryGetValue(clientId, out var existingNode)) // O(1)
{
list.Remove(existingNode); // O(1) operation, because we got the node reference
list.AddLast(clientId); // O(1) operation
return FalseTask;
}
else
{
if (set.Count == MaxSize)
{
var id = list.First.Value;
set.Remove(id); // O(1)
list.RemoveFirst(); // O(1)
}
var node = list.AddLast(clientId); // O(1)
set.Add(clientId, node); // O(1)
return TrueTask;
}
}
static readonly Task<bool> TrueTask = Task.FromResult(true);
static readonly Task<bool> FalseTask = Task.FromResult(false);
const string MaxSizeKey = "NServiceBus/InMemoryLRUGatewayDeduplication/MaxSize";
const int MaxSizeDefault = 1000;
readonly int MaxSize;
readonly LinkedList<string> list = new LinkedList<string>();
readonly Dictionary<string, LinkedListNode<string>> set = new Dictionary<string, LinkedListNode<string>>();
}
class InMemoryLRUGatewayDeduplicationPersistence : PersistenceDefinition
{
internal InMemoryLRUGatewayDeduplicationPersistence()
{
Supports<StorageType.GatewayDeduplication>(s => s.EnableFeatureByDefault<InMemoryLRUGatewayPersistence>());
}
}
class InMemoryLRUGatewayPersistence : Feature
{
internal InMemoryLRUGatewayPersistence()
{
DependsOn("Gateway");
}
/// <summary>
/// See <see cref="Feature.Setup"/>
/// </summary>
protected internal override void Setup(FeatureConfigurationContext context)
{
context.Container.ConfigureComponent<InMemoryLRUGatewayDeduplication>(DependencyLifecycle.SingleInstance);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment