Skip to content

Instantly share code, notes, and snippets.

@andreasohlund
Created December 16, 2016 13:37
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 andreasohlund/ef4b3741231eaec21d71d459b5f7c572 to your computer and use it in GitHub Desktop.
Save andreasohlund/ef4b3741231eaec21d71d459b5f7c572 to your computer and use it in GitHub Desktop.
Detects and throws an exception if the endpoint is exposed to the timeout handler issue
class TimeoutHandlerIssueDetector : Feature
{
public TimeoutHandlerIssueDetector()
{
EnableByDefault();
}
protected override void Setup(FeatureConfigurationContext context)
{
context.RegisterStartupTask(b => new DetectReusedMessages(b.Build<MessageHandlerRegistry>()));
}
internal class DetectReusedMessages : FeatureStartupTask
{
public DetectReusedMessages(MessageHandlerRegistry messageHandlerRegistry)
{
this.messageHandlerRegistry = messageHandlerRegistry;
}
protected override Task OnStart(IMessageSession session)
{
var messageTypes = messageHandlerRegistry.GetMessageTypes();
var problems = new List<string>();
foreach (var messageType in messageTypes)
{
var problematicSagas = messageHandlerRegistry.GetHandlersFor(messageType)
.Where(h => typeof(Saga).IsAssignableFrom(h.HandlerType) &&
CanHandle(typeof(IHandleTimeouts<>), h.HandlerType, messageType) &&
CanHandle(typeof(IHandleMessages<>), h.HandlerType, messageType))
.Select(h => h.HandlerType)
.Distinct()
.Select(s => $"Saga '{s.FullName}' has both a regular and a timeout handler for message '{messageType.FullName}'")
.ToList();
problems.AddRange(problematicSagas);
}
if (problems.Any())
{
var message = string.Join(Environment.NewLine, problems);
throw new Exception($"Endpoint is exposed to the timeout handler bug. {message}");
}
Debug.WriteLine($"This endpoint is not affected by the timeout handler bug ({messageTypes.Count()} message(s) checked)");
return Task.FromResult(0);
}
bool CanHandle(Type handlerInterfaceType, Type handlerType, Type messageType)
{
var interfaceType = handlerInterfaceType.MakeGenericType(messageType);
if (!interfaceType.IsAssignableFrom(handlerType))
{
return false;
}
var methodInfo = handlerType.GetInterfaceMap(interfaceType).TargetMethods.FirstOrDefault();
if (methodInfo == null)
{
return false;
}
return true;
}
protected override Task OnStop(IMessageSession session)
{
return Task.FromResult(0);
}
MessageHandlerRegistry messageHandlerRegistry;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment