private static ClassDeclarationSyntax CreateClass( ClassDeclarationSyntax parentClass, ConstructorDeclarationSyntax constructor) { ObjectCreationExpressionSyntax CreateMoq(TypeSyntax moqType) => EGH.CreateObject( moqType, SF.Argument( EGH.MemberAccess( GH.Identifier("MockBehavior"), GH.Identifier("Strict")))); var mi = new MethodInspector(constructor); var recordBuilder = new RecordBuilder($"{mi.Name}Test") .AddModifiers(Modifiers.Public); foreach (var p in mi.Parameters) { var mockedType = GetMockedType(p.Type); var moqType = GH.GenericName("Mock", mockedType); recordBuilder.AddField(moqType, MockName(p.Name), CreateMoq(moqType)); } recordBuilder.AddMethod(GenerateCreateSut(parentClass, mi)); return(recordBuilder.Build()); }
public MethodInspector GetMethodInspector(BasicDeliverEventArgs eventDetails) { try { ulong CalculateHashCode() { var resultBytes = new byte[8]; for (int i = 0; i < eventDetails.Body.Length; i++) { resultBytes[i % 8] ^= eventDetails.Body[i]; } return(BitConverter.ToUInt64(resultBytes, 0)); } Task <ulong> ghc = new Task <ulong>(CalculateHashCode); ghc.Start(); MethodInspector inspector = JsonConvert.DeserializeObject <MethodInspector>(Encoding.UTF8.GetString(eventDetails.Body)); if (inspector != null) { inspector.Hash = ghc.Result; } return(inspector); } catch (Exception) { // This message is so badly formatted we'd never be able to do anything with it. Get rid. _logger.Trace($"{nameof(MessageSubscriber)}.{nameof(ConsumeMessage)}", new LogItem("Event", "Message failed to deserialise to MethodInspector, so it is rejected"), new LogItem("MessageBody", () => Encoding.UTF8.GetString(eventDetails.Body))); return(null); } }
private static MethodDeclarationSyntax GenerateCreateSut( ClassDeclarationSyntax classDeclaration, MethodInspector constructorInspector) { var methodBuilder = new MethodBuilder(GH.IdentifierToken("CreateSut")) .Modifiers(Modifiers.Private); var constructorParameters = constructorInspector .Parameters .Select(p => SF.Argument( EGH.MemberAccess( EGH.ThisMemberAccess( GH.Identifier(MockName(p.Name)) ), GH.Identifier("Object") ) ) ); methodBuilder.ArrowBody( EGH.Arrow( EGH.CreateObject( SF.IdentifierName(classDeclaration.Identifier), constructorParameters.ToArray()))); return(methodBuilder.Build()); }
private static ClassDeclarationSyntax CreateClass( SemanticModel semanticModel, MethodDeclarationSyntax method) { var mi = new MethodInspector(method); var semanticQuery = mi.CreateSemanticQuery(semanticModel); var isTaskReturn = SymbolSemanticQuery.IsTask( semanticQuery.GetReturnType().Symbol); var parameters = mi.Parameters.Select(par => par.Type).ToList(); var recordBuilder = new RecordBuilder($"{mi.Name}Command") .AddModifiers(Modifiers.Public) .AddProperties( mi.Parameters .Select(p => (p.Type, p.Name)).ToArray()); if (isTaskReturn.IsTask()) { AddTaskUtilities(recordBuilder, Types.Bool); } else if (isTaskReturn.IsTypedTask(out var typeSymbol)) { AddTaskUtilities( recordBuilder, GH.Identifier(SymbolSemanticQuery.GetName(typeSymbol))); } return(recordBuilder.Build()); }
private void LoadActions() { try{ //drop Z3 files in VS folder. C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE Z3Link z3 = new Z3Link(); z3.ProcessSyntaxTree(MethodInspector.SyntaxTree); IDictionary <string, List <object> > varValues = z3.Solve(); //get local variables //create action for all singles //create action for all cross join variables foreach (Variable v in MethodInspector.LoadVariables()) { foreach (int assignmentLocation in v.VariableAssignmentLocations) { Action a = new Action() { Variable = v, BreakPointLocation = assignmentLocation, ValueToAssign = varValues[v.VariableName].FirstOrDefault(), }; actions.Enqueue(a); } } } catch (Exception e) { } }
private static IEnumerable <MethodDeclarationSyntax> GenerateApiControllerMethods(IEnumerable <MethodDeclarationSyntax> grainInterfaceMethods, string grainName) { var methodsDeclarations = new List <MethodDeclarationSyntax>(); foreach (var methodNode in grainInterfaceMethods) { // insert the id parameter at the end of the list of parameters var idParam = RoslynUtils.CreateParameter("string", "id"); MethodDeclarationSyntax methodDclr = RoslynUtils.AppendParameterToMethod(methodNode, idParam); methodDclr = methodDclr.AddModifiers(SF.Token(SyntaxKind.PublicKeyword)).WithSemicolonToken(SF.Token(SyntaxKind.None)); StatementSyntax getGrainStmt = SF.ParseStatement(string.Format( "var grain = _grainFactory.GetGrain<{0}>(id);\n", grainName)); MethodInspector methodInspector = new MethodInspector(methodNode); string callGrainStmt = string.Format("grain.{0}({1});", methodInspector.MethodName, string.Join(", ", methodInspector.MethodParams.Keys)); if (methodInspector.ReturnType != "Task") { callGrainStmt = callGrainStmt.Insert(0, "return "); } else { callGrainStmt = callGrainStmt.Insert(0, "await "); methodDclr = methodDclr.AddModifiers(SF.Token(SyntaxKind.AsyncKeyword)); } StatementSyntax returnStmt = SF.ParseStatement(callGrainStmt); methodsDeclarations.Add(methodDclr.WithBody(SF.Block(getGrainStmt, returnStmt))); } return(methodsDeclarations); }
private bool MessageIsDuplicate(MethodInspector inspector) { bool duplicate = _methodInspectorManager.DuplicateCheck(inspector); if (duplicate) { _logger.Trace($"{nameof(MessageSubscriber)}.{nameof(MessageIsDuplicate)}", new LogItem("Event", "Duplicate message found"), new LogItem("MessageId", inspector.Uuid.ToString)); } return(duplicate); }
private static MethodDeclarationSyntax GenerateMethodDeclaration(MethodInspector methodInspector) { MethodDeclarationSyntax methodDclr = SF.MethodDeclaration(SF.ParseTypeName(methodInspector.ReturnType), SF.Identifier(methodInspector.MethodName)); foreach (KeyValuePair <string, string> keyValuePair in methodInspector.MethodParams) { string paramType = keyValuePair.Value; string paramName = keyValuePair.Key; methodDclr = RoslynUtils.AppendParameterToMethod(methodDclr, RoslynUtils.CreateParameter(paramType, paramName)); } return(methodDclr); }
private static ClassDeclarationSyntax GenerateWriteGrain(ClassDeclarationSyntax grainClass, ITypeSymbol swmrInterface, int readReplicaCount) { string grainName = grainClass.Identifier.Text; string writerGrainName = SwmrUtils.GetWriteInterfaceName(grainName); string writerInterfaceName = SwmrUtils.GetWriteInterfaceName(swmrInterface.Name); ClassDeclarationSyntax writerGrain = GenerateClassSqueleton(writerGrainName).WithBaseList(RoslynUtils.BaseList(new[] { "Grain", writerInterfaceName })); writerGrain = RoslynUtils.AddField(writerGrain, "ITopology<string>", "_topology"); writerGrain = writerGrain.AddMembers(GenerateOnActivateAsyncMethod(readReplicaCount)); string readReplicaInterfaceName = SwmrUtils.GetReadReplicaInterfaceName(swmrInterface.Name); foreach (ISymbol member in swmrInterface.GetMembers()) { IMethodSymbol methodSymbol = member as IMethodSymbol; if (methodSymbol == null || IsReadOnlyMethod(methodSymbol) || new MethodInspector(methodSymbol).MethodName == "GetState") { continue; } MethodInspector methodInspector = new MethodInspector(methodSymbol); MethodDeclarationSyntax methodImpl = GenerateMethodDeclaration(methodInspector); methodImpl = SwmrUtils.AddSessionIdParameter(methodImpl).AddModifiers(SF.Token(SyntaxKind.PublicKeyword), SF.Token(SyntaxKind.AsyncKeyword)).WithSemicolonToken(SF.Token(SyntaxKind.None)); BlockSyntax statmentBlock = SF.Block(); statmentBlock = AddStatement(statmentBlock, "string grainId = this.GetPrimaryKeyString();"); statmentBlock = AddStatement(statmentBlock, string.Format("{0} grain = GrainFactory.GetGrain<{0}>(grainId);", swmrInterface.Name)); statmentBlock = AddStatement(statmentBlock, String.Format("{0} await grain.{1}({2});", methodInspector.ReturnType != "Task"? "var result =" : "", methodInspector.MethodName, string.Join(", ", methodInspector.MethodParams.Keys))); statmentBlock = AddStatement(statmentBlock, "GrainState state = await grain.GetState();"); statmentBlock = AddStatement(statmentBlock, "string sessionNode = _topology.GetNode(sessionId);"); statmentBlock = AddStatement(statmentBlock, "IEnumerable<string> otherNodes = _topology.Nodes.Where(node => node != sessionNode);"); ForEachStatementSyntax forEachStatement = SF.ForEachStatement( SF.PredefinedType(SF.Token(SyntaxKind.StringKeyword)), SF.Identifier("node"), SF.IdentifierName("otherNodes"), SF.Block(SF.ParseStatement(GenerateSetStateStmt(readReplicaInterfaceName, @"node"))) ); statmentBlock = statmentBlock.AddStatements(forEachStatement); statmentBlock = AddStatement(statmentBlock, (string.Format("{0} {1}", "await", GenerateSetStateStmt(readReplicaInterfaceName, @"sessionNode")))); if (methodInspector.ReturnType != "Task") { statmentBlock = AddStatement(statmentBlock, "return result;"); } methodImpl = methodImpl.WithBody(statmentBlock); writerGrain = writerGrain.AddMembers(methodImpl); } return(writerGrain); }
private Type GetMessageHandlers(MethodInspector inspector) { lock (MethodHandlerDictionary) { if (!MethodHandlerDictionary.ContainsKey(inspector.Method)) { var bestHandler = GetBestHandlerFor(inspector); if (bestHandler != null) { MethodHandlerDictionary[inspector.Method] = bestHandler; } } return(MethodHandlerDictionary[inspector.Method]); } }
private Type GetBestHandlerFor(MethodInspector inspector) { var messageHandlerTypes = _messageHandlerTypes ?? (_messageHandlerTypes = _container.GetAttributedTypes <HandlerAttribute>(typeof(IMessageHandler2 <,>))); _logger.Trace($"{nameof(MessageSubscriber)}.{nameof(GetMessageHandlers)}", new LogItem("Event", $"Found the following types that might be able to handle this message: {string.Join(",", messageHandlerTypes.Select(t => t.Key.Name))}"), new LogItem("MessageId", inspector.Uuid.ToString)); Type handlersMatchingMethod = messageHandlerTypes.FirstOrDefault(mht => mht.Value.Any(ha => ha.Method == inspector.Method)).Key; if (handlersMatchingMethod == null) { var blanketHandlers = messageHandlerTypes.Where(mht => mht.Key.GetGenericArguments().All(arg => arg.IsGenericParameter) && mht.Value.Any(ha => ha.Method == "*")); return(blanketHandlers.First().Key); } return(handlersMatchingMethod); }
private static ClassDeclarationSyntax GenerateReadGrain(ClassDeclarationSyntax grainClass, ITypeSymbol swmrInterface, int readReplicaCount) { string readGrainName = SwmrUtils.GetReadInterfaceName(grainClass.Identifier.Text); string readerInterfaceName = SwmrUtils.GetReadInterfaceName(swmrInterface.Name); ClassDeclarationSyntax readGrain = GenerateClassSqueleton(readGrainName).WithAttributeLists(AttributeUtils.AttributeListList(AttributeUtils.Attribute(StatelessWorkerAttributeName))).WithBaseList(RoslynUtils.BaseList(new[] { "Grain", readerInterfaceName })); readGrain = RoslynUtils.AddField(readGrain, "ITopology<string>", "_topology"); readGrain = readGrain.AddMembers(GenerateOnActivateAsyncMethod(readReplicaCount)); string readReplicaInterfaceName = SwmrUtils.GetReadReplicaInterfaceName(swmrInterface.Name); foreach (ISymbol member in swmrInterface.GetMembers()) { IMethodSymbol methodSymbol = member as IMethodSymbol; if (methodSymbol == null || !IsReadOnlyMethod(methodSymbol)) { continue; } MethodInspector methodInspector = new MethodInspector(methodSymbol); string parameters = "string sessionId"; if (methodInspector.MethodParams.Any()) { parameters = string.Join(", ", methodInspector.MethodParams.Select(param => string.Format("{0} {1}", param.Value, param.Key))) + " ," + parameters; } var method = RoslynUtils.ParseMethod(string.Format( @" public {0} {1}({2}) {{ string sessionNode = _topology.GetNode(sessionId); var readReplica = GrainFactory.GetGrain<{3}>(sessionNode); return readReplica.{1}({4}); }}", methodInspector.ReturnType, methodInspector.MethodName, parameters, readReplicaInterfaceName, string.Join(", ", methodInspector.MethodParams.Keys))); readGrain = readGrain.AddMembers( method.WithLeadingTrivia(SF.EndOfLine(""))); } return(readGrain); }
public MethodSemanticQuery(SemanticModel model, MethodInspector inspector) { this.model = model; this.inspector = inspector; }
private static MethodDeclarationSyntax GenerateMethodDeclaration(MethodInspector methodInspector) { MethodDeclarationSyntax methodDclr = SF.MethodDeclaration(SF.ParseTypeName(methodInspector.ReturnType), SF.Identifier(methodInspector.MethodName)); foreach (KeyValuePair<string, string> keyValuePair in methodInspector.MethodParams) { string paramType = keyValuePair.Value; string paramName = keyValuePair.Key; methodDclr = RoslynUtils.AppendParameterToMethod(methodDclr, RoslynUtils.CreateParameter(paramType, paramName)); } return methodDclr; }
private static ClassDeclarationSyntax GenerateWriteGrain(ClassDeclarationSyntax grainClass, ITypeSymbol swmrInterface, int readReplicaCount) { string grainName = grainClass.Identifier.Text; string writerGrainName = SwmrUtils.GetWriteInterfaceName(grainName); string writerInterfaceName = SwmrUtils.GetWriteInterfaceName(swmrInterface.Name); ClassDeclarationSyntax writerGrain = GenerateClassSqueleton(writerGrainName).WithBaseList(RoslynUtils.BaseList(new[] { "Grain", writerInterfaceName })); writerGrain = RoslynUtils.AddField(writerGrain, "ITopology<string>", "_topology"); writerGrain = writerGrain.AddMembers(GenerateOnActivateAsyncMethod(readReplicaCount)); string readReplicaInterfaceName = SwmrUtils.GetReadReplicaInterfaceName(swmrInterface.Name); foreach (ISymbol member in swmrInterface.GetMembers()) { IMethodSymbol methodSymbol = member as IMethodSymbol; if (methodSymbol == null || IsReadOnlyMethod(methodSymbol) || new MethodInspector(methodSymbol).MethodName == "GetState") { continue; } MethodInspector methodInspector = new MethodInspector(methodSymbol); MethodDeclarationSyntax methodImpl = GenerateMethodDeclaration(methodInspector); methodImpl = SwmrUtils.AddSessionIdParameter(methodImpl).AddModifiers(SF.Token(SyntaxKind.PublicKeyword), SF.Token(SyntaxKind.AsyncKeyword)).WithSemicolonToken(SF.Token(SyntaxKind.None)); BlockSyntax statmentBlock = SF.Block(); statmentBlock = AddStatement(statmentBlock, "string grainId = this.GetPrimaryKeyString();"); statmentBlock = AddStatement(statmentBlock, string.Format("{0} grain = GrainFactory.GetGrain<{0}>(grainId);", swmrInterface.Name)); statmentBlock = AddStatement(statmentBlock, String.Format("{0} await grain.{1}({2});", methodInspector.ReturnType != "Task"? "var result =" : "", methodInspector.MethodName, string.Join(", ", methodInspector.MethodParams.Keys))); statmentBlock = AddStatement(statmentBlock, "GrainState state = await grain.GetState();"); statmentBlock = AddStatement(statmentBlock, "string sessionNode = _topology.GetNode(sessionId);"); statmentBlock = AddStatement(statmentBlock, "IEnumerable<string> otherNodes = _topology.Nodes.Where(node => node != sessionNode);"); ForEachStatementSyntax forEachStatement = SF.ForEachStatement( SF.PredefinedType(SF.Token(SyntaxKind.StringKeyword)), SF.Identifier("node"), SF.IdentifierName("otherNodes"), SF.Block(SF.ParseStatement(GenerateSetStateStmt(readReplicaInterfaceName, @"node"))) ); statmentBlock = statmentBlock.AddStatements(forEachStatement); statmentBlock = AddStatement(statmentBlock, (string.Format("{0} {1}", "await", GenerateSetStateStmt(readReplicaInterfaceName, @"sessionNode")))); if (methodInspector.ReturnType != "Task") { statmentBlock = AddStatement(statmentBlock, "return result;"); } methodImpl = methodImpl.WithBody(statmentBlock); writerGrain = writerGrain.AddMembers(methodImpl); } return writerGrain; }
private static ClassDeclarationSyntax GenerateReadGrain(ClassDeclarationSyntax grainClass, ITypeSymbol swmrInterface, int readReplicaCount) { string readGrainName = SwmrUtils.GetReadInterfaceName(grainClass.Identifier.Text); string readerInterfaceName = SwmrUtils.GetReadInterfaceName(swmrInterface.Name); ClassDeclarationSyntax readGrain = GenerateClassSqueleton(readGrainName).WithAttributeLists(AttributeUtils.AttributeListList(AttributeUtils.Attribute(StatelessWorkerAttributeName))).WithBaseList(RoslynUtils.BaseList(new[] { "Grain", readerInterfaceName })); readGrain = RoslynUtils.AddField(readGrain, "ITopology<string>", "_topology"); readGrain = readGrain.AddMembers(GenerateOnActivateAsyncMethod(readReplicaCount)); string readReplicaInterfaceName = SwmrUtils.GetReadReplicaInterfaceName(swmrInterface.Name); foreach (ISymbol member in swmrInterface.GetMembers()) { IMethodSymbol methodSymbol = member as IMethodSymbol; if (methodSymbol == null || !IsReadOnlyMethod(methodSymbol)) { continue; } MethodInspector methodInspector = new MethodInspector(methodSymbol); string parameters = "string sessionId"; if (methodInspector.MethodParams.Any()) { parameters = string.Join(", ", methodInspector.MethodParams.Select(param => string.Format("{0} {1}", param.Value, param.Key))) + " ," + parameters; } var method = RoslynUtils.ParseMethod(string.Format( @" public {0} {1}({2}) {{ string sessionNode = _topology.GetNode(sessionId); var readReplica = GrainFactory.GetGrain<{3}>(sessionNode); return readReplica.{1}({4}); }}", methodInspector.ReturnType, methodInspector.MethodName, parameters, readReplicaInterfaceName, string.Join(", ", methodInspector.MethodParams.Keys))); readGrain = readGrain.AddMembers( method.WithLeadingTrivia(SF.EndOfLine(""))); } return readGrain; }
private static IEnumerable<MethodDeclarationSyntax> GenerateApiControllerMethods(IEnumerable<MethodDeclarationSyntax> grainInterfaceMethods, string grainName) { var methodsDeclarations = new List<MethodDeclarationSyntax>(); foreach (var methodNode in grainInterfaceMethods) { // insert the id parameter at the end of the list of parameters var idParam = RoslynUtils.CreateParameter("string", "id"); MethodDeclarationSyntax methodDclr = RoslynUtils.AppendParameterToMethod(methodNode, idParam); methodDclr = methodDclr.AddModifiers(SF.Token(SyntaxKind.PublicKeyword)).WithSemicolonToken(SF.Token(SyntaxKind.None)); StatementSyntax getGrainStmt = SF.ParseStatement(string.Format( "var grain = _grainFactory.GetGrain<{0}>(id);\n", grainName)); MethodInspector methodInspector = new MethodInspector(methodNode); string callGrainStmt = string.Format("grain.{0}({1});", methodInspector.MethodName, string.Join(", ", methodInspector.MethodParams.Keys)); if (methodInspector.ReturnType != "Task") { callGrainStmt = callGrainStmt.Insert(0, "return "); } else { callGrainStmt = callGrainStmt.Insert(0, "await "); methodDclr = methodDclr.AddModifiers(SF.Token(SyntaxKind.AsyncKeyword)); } StatementSyntax returnStmt = SF.ParseStatement(callGrainStmt); methodsDeclarations.Add(methodDclr.WithBody(SF.Block(getGrainStmt, returnStmt))); } return methodsDeclarations; }
public Task ConsumeMessage(object sender, BasicDeliverEventArgs eventDetails) { try { inProgressMessages++; if (eventDetails?.Body == null || eventDetails.Body.Length < 1) { return(RejectMessageWith(DiscardedMessageReason.MissingMessageBody, eventDetails)); } // Deserialise into a class containing only Method and UUID - this also generates a hash MethodInspector inspector = GetMethodInspector(eventDetails); if (inspector == null) { return(RejectMessageWith(DiscardedMessageReason.MethodDeserialisationError, eventDetails)); } _logger.Trace($"{nameof(MessageSubscriber)}.{nameof(ConsumeMessage)}", new LogItem("Event", "Message routed"), new LogItem("Calculated hashcode", inspector.Hash), new LogItem("MessageId", inspector.Uuid.ToString), new LogItem("MessageMethod", inspector.Method)); if (MessageIsDuplicate(inspector)) { return(RejectMessageWith(DiscardedMessageReason.Duplicate, eventDetails)); } Type handlerType = GetMessageHandlers(inspector); if (handlerType == null) { _logger.Trace($"{nameof(MessageSubscriber)}.{nameof(ConsumeMessage)}", new LogItem("Event", "No suitable handler found for Method " + inspector.Method)); // We can't process this message, so we'll Ack it. _methodInspectorManager.Register(inspector); // we don't want to see it again return(RejectMessageWith(DiscardedMessageReason.NoHandler, eventDetails)); } Type[] genericArguments = GetGenericArguments(handlerType, inspector.Uuid); if (handlerType.GetTypeInfo().ContainsGenericParameters) { handlerType = handlerType.MakeGenericType(genericArguments); } string bodyAsString = Encoding.UTF8.GetString(eventDetails.Body); if (!ConstructMessage(out object message, genericArguments, bodyAsString, inspector.Uuid)) { _logger.Trace($"{nameof(MessageSubscriber)}.{nameof(ConsumeMessage)}", new LogItem("Event", "The Message could not be constructed, so it's been discarded.")); _methodInspectorManager.Register(inspector); // we don't want to see it again // This is a Permanent Failure; if we couldn't construct the Message object now, processing it again won't help. return(RejectMessageWith(DiscardedMessageReason.MessageDeserialisationError, eventDetails)); } Type messageType = message.GetType(); PropertyInfo need; lock (NeedPropertyCache) { if (!NeedPropertyCache.ContainsKey(messageType)) { NeedPropertyCache.Add(messageType, messageType.GetProperty(nameof(Message <object, object> .Need))); } need = NeedPropertyCache[messageType]; } if (need.GetValue(message) == null) { _logger.Warn($"{nameof(MessageSubscriber)}.{nameof(ConsumeMessage)}", new LogItem("Event", "Message has no Need"), new LogItem("MessageId", inspector.Uuid.ToString)); _methodInspectorManager.Register(inspector); // we don't want to see it again // This is a Permanent Failure; if there's no Need in the message now, processing it again won't change anything. return(RejectMessageWith(DiscardedMessageReason.MissingNeed, eventDetails)); } HandlerAttribute handlerAttribute = handlerType.GetTypeInfo().GetCustomAttributes <HandlerAttribute>().FirstOrDefault(a => a.Method == inspector.Method); if (!ProcessAcceptanceBehaviours(handlerAttribute, messageType, message)) { _methodInspectorManager.Register(inspector); // we don't want to see it again return(RejectMessageWith(DiscardedMessageReason.AcceptanceBehaviourPrecondition, eventDetails)); } _logger.Trace($"{nameof(MessageSubscriber)}.{nameof(ConsumeMessage)}", new LogItem("Event", "Constructing handler"), new LogItem("MessageId", inspector.Uuid.ToString), new LogItem("HandlerName", handlerType.Name)); var stopWatch = Stopwatch.StartNew(); CompletionAction invocationResult = InvokeHandleMethod(inspector.Uuid, handlerType, message); stopWatch.Stop(); _metrics.RecordProcessedMessage(handlerType.Name, stopWatch.Elapsed.TotalMilliseconds); if (invocationResult == CompletionAction.Republish) { publishMethod = publishMethod ?? _queueWrapper.GetType().GetMethod(nameof(_queueWrapper.PublishMessage)); publishMethod.MakeGenericMethod(genericArguments).Invoke(_queueWrapper, new object[] { message, inspector.Uuid }); } // Any exceptions thrown up to this point *are probably* Temporary Failures: // Permanent Failures will have been dealt with by local Exception Handling, // and the code will continue to this point. _methodInspectorManager.Register(inspector); _queueWrapper.AcknowledgeMessage(eventDetails); } catch (Exception e) { _logger.Exception($"{nameof(MessageSubscriber)}.{nameof(ConsumeMessage)}", "Failure during consuming of message", e); throw; } finally { inProgressMessages--; } return(Task.CompletedTask); }