Skip to content

Commit b21f57f

Browse files
committed
chore(msg.router): remove unnecessary exception handling in messge router
1 parent 83c4dc3 commit b21f57f

File tree

2 files changed

+134
-102
lines changed

2 files changed

+134
-102
lines changed

src/Arcus.Messaging.Abstractions/MessageHandling/MessageHandler.cs

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -153,18 +153,18 @@ private static Func<object, MessageHandlerSummary, bool> DetermineMessageBodyFil
153153

154154
if (rawMessage is not TMessage message)
155155
{
156-
summary.AddFailed("custom body filter failed", ("requires type", typeof(TMessage).Name));
156+
summary.AddFailed("custom body filter failed", check => check.AddMember("requires type", typeof(TMessage).Name));
157157
return false;
158158
}
159159

160160
bool matches = messageBodyFilter(message);
161161
if (matches)
162162
{
163-
summary.AddPassed("custom body filter passed", ("against type", typeof(TMessage).Name));
163+
summary.AddPassed("custom body filter passed", check => check.AddMember("against type", typeof(TMessage).Name));
164164
return true;
165165
}
166166

167-
summary.AddFailed("custom body filter failed", reason: "returns 'false'");
167+
summary.AddFailed("custom body filter failed", check => check.AddReason("returns 'false'"));
168168
return false;
169169
};
170170
}
@@ -180,7 +180,7 @@ private static Func<MessageContext, MessageHandlerSummary, bool> DetermineMessag
180180

181181
if (jobId is not null && rawContext.JobId != jobId)
182182
{
183-
summary.AddFailed("custom context filter failed", ("requires job ID", rawContext.JobId));
183+
summary.AddFailed("custom context filter failed", check => check.AddMember("requires job ID", rawContext.JobId));
184184
return false;
185185
}
186186

@@ -191,18 +191,18 @@ private static Func<MessageContext, MessageHandlerSummary, bool> DetermineMessag
191191

192192
if (rawContext is not TMessageContext messageContext)
193193
{
194-
summary.AddFailed("custom context filter filter failed", ("requires type", typeof(TMessageContext).Name));
194+
summary.AddFailed("custom context filter failed", check => check.AddMember("requires type", typeof(TMessageContext).Name));
195195
return false;
196196
}
197197

198198
bool matches = messageContextFilter(messageContext);
199199
if (matches)
200200
{
201-
summary.AddPassed("custom context filter passed", ("against type", typeof(TMessageContext).Name));
201+
summary.AddPassed("custom context filter passed", check => check.AddMember("against type", typeof(TMessageContext).Name));
202202
return true;
203203
}
204204

205-
summary.AddFailed("custom context filter failed", reason: "returns 'false'");
205+
summary.AddFailed("custom context filter failed", check => check.AddReason("returns 'false'"));
206206
return false;
207207
};
208208
}
@@ -283,19 +283,34 @@ internal async Task<MessageResult> TryCustomDeserializeMessageAsync(string messa
283283
return MessageResult.Failure("n/a");
284284
}
285285

286-
Task<MessageResult> deserializeMessageAsync = _messageBodySerializer.DeserializeMessageAsync(message);
287286
Type serializerType = _messageBodySerializer.GetType();
288-
289-
if (deserializeMessageAsync is null)
287+
MessageResult result = null;
288+
try
290289
{
291-
summary.AddFailed("custom body parsing failed", ("using type", serializerType.Name), "returns 'null'");
292-
return MessageResult.Failure("n/a");
293-
}
290+
Task<MessageResult> deserializeMessageAsync = _messageBodySerializer.DeserializeMessageAsync(message);
294291

295-
MessageResult result = await deserializeMessageAsync;
296-
if (result is null)
292+
if (deserializeMessageAsync is null)
293+
{
294+
summary.AddFailed("custom body parsing failed",
295+
check => check.AddMember("using type", serializerType.Name)
296+
.AddReason("returns 'null'"));
297+
298+
return MessageResult.Failure("n/a");
299+
}
300+
301+
result = await deserializeMessageAsync;
302+
if (result is null)
303+
{
304+
summary.AddFailed("custom body parsing failed",
305+
check => check.AddMember("using type", serializerType.Name)
306+
.AddReason("returns 'null'"));
307+
308+
return MessageResult.Failure("n/a");
309+
}
310+
}
311+
catch (Exception exception)
297312
{
298-
summary.AddFailed("custom body parsing failed", ("using type", serializerType.Name), "returns 'null'");
313+
summary.AddFailed(exception, "custom body parsing failed", check => check.AddMember("using type", serializerType.Name));
299314
return MessageResult.Failure("n/a");
300315
}
301316

@@ -304,15 +319,18 @@ internal async Task<MessageResult> TryCustomDeserializeMessageAsync(string messa
304319
Type deserializedMessageType = result.DeserializedMessage.GetType();
305320
if (deserializedMessageType == MessageType || deserializedMessageType.IsSubclassOf(MessageType))
306321
{
307-
summary.AddPassed("custom body parsing passed", ("using type", serializerType.Name));
322+
summary.AddPassed("custom body parsing passed", check => check.AddMember("using type", serializerType.Name));
308323
return result;
309324
}
310325

311-
summary.AddFailed("custom body parsing failed", ("using type", serializerType.Name), ("requires type", MessageType.Name), ("but got type", deserializedMessageType.Name));
326+
summary.AddFailed("custom body parsing failed",
327+
check => check.AddMember("using deserializer type", serializerType.Name)
328+
.AddReason($"requires message type={MessageType.Name}, got type={deserializedMessageType.Name}"));
329+
312330
return MessageResult.Failure("n/a");
313331
}
314332

315-
summary.AddFailed(result.Exception, "custom body parsing failed", result.ErrorMessage);
333+
summary.AddFailed(result.Exception, "custom body parsing failed", check => check.AddReason(result.ErrorMessage));
316334
return MessageResult.Failure("n/a");
317335
}
318336

src/Arcus.Messaging.Abstractions/MessageHandling/MessageRouter.cs

Lines changed: 97 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Collections.ObjectModel;
44
using System.Linq;
5+
using System.Text;
56
using System.Text.Json;
67
using System.Text.Json.Serialization;
78
using System.Threading;
@@ -107,34 +108,27 @@ protected async Task<MessageProcessingResult> RouteMessageThroughRegisteredHandl
107108
return NoHandlersRegistered(messageContext.MessageId);
108109
}
109110

110-
try
111+
int skippedHandlers = 0;
112+
bool hasGoneThroughMessageHandler = false;
113+
114+
foreach (var handler in handlers)
111115
{
112-
int skippedHandlers = 0;
113-
bool hasGoneThroughMessageHandler = false;
116+
MessageProcessingResult result = await ProcessMessageHandlerAsync(handler, messageBody, messageContext, correlationInfo, cancellation);
117+
hasGoneThroughMessageHandler = result.IsSuccessful || result.Error is MessageProcessingError.ProcessingInterrupted;
114118

115-
foreach (var handler in handlers)
119+
if (result.IsSuccessful)
116120
{
117-
MessageProcessingResult result = await ProcessMessageHandlerAsync(handler, messageBody, messageContext, correlationInfo, cancellation);
118-
hasGoneThroughMessageHandler = result.IsSuccessful || result.Error is MessageProcessingError.ProcessingInterrupted;
119-
120-
if (result.IsSuccessful)
121-
{
122-
Logger.LogMessageProcessedSummary(messageContext.MessageId, handler.MessageHandlerType, skippedHandlers);
123-
return result;
124-
}
125-
126-
skippedHandlers++;
121+
Logger.LogMessageProcessedSummary(messageContext.MessageId, handler.MessageHandlerType, skippedHandlers);
122+
return result;
127123
}
128124

129-
return hasGoneThroughMessageHandler
130-
? MatchedHandlerFailed(messageContext.MessageId)
131-
: NoMatchedHandler(messageContext.MessageId);
132-
}
133-
catch (Exception exception)
134-
{
135-
return ExceptionDuringRouting(exception, messageContext.MessageId);
125+
skippedHandlers++;
136126
}
137127

128+
return hasGoneThroughMessageHandler
129+
? MatchedHandlerFailed(messageContext.MessageId)
130+
: NoMatchedHandler(messageContext.MessageId);
131+
138132
MessageProcessingResult NoHandlersRegistered(string messageId)
139133
{
140134
Logger.LogNoHandlersRegistered(messageId);
@@ -152,12 +146,6 @@ MessageProcessingResult MatchedHandlerFailed(string messageId)
152146
Logger.LogMatchedHandlerFailedToProcessMessage(messageId);
153147
return MessageProcessingResult.Failure(messageId, MessageProcessingError.MatchedHandlerFailed, MatchedHandlerFailedMessage);
154148
}
155-
156-
MessageProcessingResult ExceptionDuringRouting(Exception exception, string messageId)
157-
{
158-
Logger.LogExceptionDuringRouting(exception, messageId);
159-
return MessageProcessingResult.Failure(messageId, MessageProcessingError.ProcessingInterrupted, ExceptionDuringRoutingMessage, exception);
160-
}
161149
}
162150

163151
private async Task<MessageProcessingResult> ProcessMessageHandlerAsync<TMessageContext>(
@@ -206,7 +194,7 @@ MessageProcessingResult MatchedHandlerSkipped()
206194

207195
MessageProcessingResult MatchedHandlerFailed(Exception exception, string errorMessage)
208196
{
209-
summary.AddFailed(exception, "message processing failed", errorMessage);
197+
summary.AddFailed(exception, "message processing failed", check => check.AddReason(errorMessage));
210198

211199
Logger.LogMessageFailedInHandler(messageType, context.MessageId, handler.MessageHandlerType, summary);
212200
return MessageProcessingResult.Failure(context.MessageId, MessageProcessingError.ProcessingInterrupted, "n/a");
@@ -278,11 +266,11 @@ private async Task<MessageResult> DeserializeMessageAsync(MessageHandler handler
278266
object deserializedByType = JsonSerializer.Deserialize(messageBody, handlerMessageType, _jsonOptions);
279267
if (deserializedByType != null)
280268
{
281-
summary.AddPassed("default JSON body parsing passed", ("additional members", Options.Deserialization.AdditionalMembers));
269+
summary.AddPassed("default JSON body parsing passed", check => check.AddMember("additional members", Options.Deserialization.AdditionalMembers.ToString()));
282270
return MessageResult.Success(deserializedByType);
283271
}
284272

285-
summary.AddFailed("default JSON body parsing failed", reason: "returns 'null'");
273+
summary.AddFailed("default JSON body parsing failed", check => check.AddReason("returns 'null'"));
286274
return MessageResult.Failure("n/a");
287275
}
288276
catch (JsonException exception)
@@ -349,9 +337,6 @@ internal static partial class MessageRouterLoggerExtensions
349337
[LoggerMessage(LogLevel.Error, "Message '{MessageId}' [Failed in] message pump => ✗ " + MatchedHandlerFailedMessage)]
350338
internal static partial void LogMatchedHandlerFailedToProcessMessage(this ILogger logger, string messageId);
351339

352-
[LoggerMessage(LogLevel.Critical, "Message '{MessageId}' [Failed in] message pump => ✗ " + ExceptionDuringRoutingMessage)]
353-
internal static partial void LogExceptionDuringRouting(this ILogger logger, Exception exception, string messageId);
354-
355340
internal static void LogMessageSkippedByHandler(this ILogger logger, string messageId, Type messageHandlerType, MessageHandlerSummary summary)
356341
{
357342
LogMessageSkippedByHandler(logger, summary.OccurredException, messageId, messageHandlerType.Name, summary);
@@ -411,78 +396,107 @@ internal class MessageHandlerSummary
411396
_ => new AggregateException(_exceptions)
412397
};
413398

414-
/// <summary>
415-
/// Adds a passed check to the summary.
416-
/// </summary>
417-
/// <param name="description">The message that describes in a short manner the check that was passed.</param>
418-
/// <param name="members">The additional key-value pair members that were involved in the check.</param>
419-
internal void AddPassed(string description, params (string, object)[] members)
399+
internal class MessageHandlerCheckBuilder
420400
{
421-
ArgumentNullException.ThrowIfNull(description);
401+
private readonly Collection<(string memberName, string memberValue)> _members = [];
402+
private string _reason;
403+
private readonly StringBuilder _result = new();
422404

423-
string membersDescription = members.Length > 0
424-
? $" ({string.Join(", ", members.Select(m => m.Item1 + "=" + m.Item2))})"
425-
: string.Empty;
405+
private MessageHandlerCheckBuilder(string description)
406+
{
407+
ArgumentException.ThrowIfNullOrWhiteSpace(description);
408+
_result.Append(description);
409+
}
426410

427-
_lines.Add("✓ " + description + membersDescription);
428-
}
411+
internal static MessageHandlerCheckBuilder Passed(string description) => new("✓ " + description);
412+
internal static MessageHandlerCheckBuilder Failed(string description) => new("✗ " + description);
429413

430-
/// <summary>
431-
/// Adds a failed check to the summary.
432-
/// </summary>
433-
/// <param name="exception">The optional exception that occured during the check.</param>
434-
/// <param name="description">The message that describes in a short manner the check that was failed.</param>
435-
/// <param name="reason">The message that explains the reason why the check failed.</param>
436-
internal void AddFailed(Exception exception, string description, string reason = "exception thrown")
437-
{
438-
if (exception is not null)
414+
/// <summary>
415+
/// Adds a key-value pair member to the pre-check message - acts as additional context (i.e. 'using type=MyType').
416+
/// </summary>
417+
internal MessageHandlerCheckBuilder AddMember(string memberName, string memberValue)
439418
{
440-
_exceptions.Add(exception);
419+
_members.Add((memberName, memberValue));
420+
return this;
441421
}
442422

443-
AddFailed(description, reason);
423+
/// <summary>
424+
/// Adds a final reason why the pre-check acted like it did.
425+
/// </summary>
426+
internal MessageHandlerCheckBuilder AddReason(string reason)
427+
{
428+
_reason = reason;
429+
return this;
430+
}
431+
432+
/// <summary>
433+
/// Returns a string that represents the current object.
434+
/// </summary>
435+
/// <returns>A string that represents the current object.</returns>
436+
public override string ToString()
437+
{
438+
if (_members.Count > 0)
439+
{
440+
_result.Append(" (");
441+
_result.AppendJoin(", ", _members.Select(m => $"{m.memberName}={m.memberValue}"));
442+
_result.Append(')');
443+
}
444+
445+
if (_reason != null)
446+
{
447+
_result.Append(": ");
448+
_result.Append(_reason);
449+
}
450+
451+
return _result.ToString();
452+
}
444453
}
445454

446455
/// <summary>
447-
/// Adds a failed check to the summary.
456+
/// Adds a passed pre-check line to the summary.
448457
/// </summary>
449-
/// <param name="description">The message that describes in a short manner the check that was failed.</param>
450-
/// <param name="reason">The message that explains the reason why the check failed.</param>
451-
internal void AddFailed(string description, string reason)
458+
/// <param name="description">The short description of the pre-check.</param>
459+
/// <param name="configureCheck">The additional information around the pre-check, formatted on the same line.</param>
460+
internal void AddPassed(string description, Action<MessageHandlerCheckBuilder> configureCheck = null)
452461
{
453-
ArgumentNullException.ThrowIfNull(description);
454-
ArgumentNullException.ThrowIfNull(reason);
462+
var builder = MessageHandlerCheckBuilder.Passed(description);
463+
configureCheck?.Invoke(builder);
455464

456-
AddFailed(description + " (" + reason + ")");
465+
_lines.Add(builder.ToString());
457466
}
458467

459468
/// <summary>
460-
/// Adds a failed check to the summary.
469+
/// Adds a failed pre-check line to the summary.
461470
/// </summary>
462-
/// <param name="description">The message that describes in a short manner the check that was failed.</param>
463-
/// <param name="members">The additional members that were involved in the check (both single values as tuples are supported).</param>
464-
internal void AddFailed(string description, params object[] members)
471+
/// <param name="exception">
472+
/// The occurred exception that caused the pre-check to fail
473+
/// - only here to track exceptions (<see cref="OccurredException"/>), not to expose information in the logged line.
474+
/// </param>
475+
/// <param name="description">The short description of the pre-check.</param>
476+
/// <param name="configureCheck">The additional information around the pre-check, formatted on the same line.</param>
477+
internal void AddFailed(Exception exception, string description, Action<MessageHandlerCheckBuilder> configureCheck = null)
465478
{
466-
ArgumentNullException.ThrowIfNull(description);
467-
ArgumentNullException.ThrowIfNull(members);
479+
ArgumentNullException.ThrowIfNull(exception);
480+
_exceptions.Add(exception);
468481

469-
string membersDescription = members.Length > 1
470-
? $" ({string.Join(", ", members.Select(m =>
471-
{
472-
return m switch
473-
{
474-
(string name, string value) => $"{name}={value}",
475-
_ => m.ToString()
476-
};
477-
}))}"
478-
: string.Empty;
479-
480-
AddFailed(description + membersDescription);
482+
AddFailed(description, check =>
483+
{
484+
check.AddReason("exception thrown");
485+
configureCheck?.Invoke(check);
486+
});
481487
}
482488

483-
private void AddFailed(string description)
489+
/// <summary>
490+
/// Adds a failed pre-check line to the summary.
491+
/// </summary>
492+
/// <param name="description">The short description of the pre-check.</param>
493+
/// <param name="configureCheck">The additional information around the pre-check, formatted on the same line.</param>
494+
internal void AddFailed(string description, Action<MessageHandlerCheckBuilder> configureCheck = null)
484495
{
485-
_lines.Add("✗ " + description);
496+
var builder = MessageHandlerCheckBuilder.Failed(description);
497+
configureCheck?.Invoke(builder);
498+
499+
_lines.Add(builder.ToString());
486500
}
487501

488502
/// <summary>

0 commit comments

Comments
 (0)