Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public Task RecordFailedProcessingAttempt(MessageContext context,
Groups = groups,
HeadersJson = MessageHeaders.Write(processingAttempt.Headers),
MessageId = processingAttempt.MessageId,
MessageType = TruncateForColumn(GetMetadata<string>(processingAttempt, "MessageType")),
MessageType = TruncateTypeName(GetMetadata<string>(processingAttempt, "MessageType")),
TimeSent = GetMetadata<DateTime?>(processingAttempt, "TimeSent"),
ConversationId = GetMetadata<string>(processingAttempt, "ConversationId"),
SendingEndpointName = sendingEndpoint?.Name,
Expand Down Expand Up @@ -70,13 +70,10 @@ public Task RecordSuccessfulRetry(string retriedMessageUniqueId, DateTime succee
}

// The MessageType column is length-bounded (ColumnLengths.ShortTextLength) so that it can be
// an index key serving sort=message_type. The cap is enforced here, like the body size limit
// above, because it is an EFCore storage limit the persister owns rather than a shared
// ingestion rule. EnclosedMessageTypes' first comma token is a type's full name, so the cap can
// only ever bite on pathological generic names, where a truncated sort key still sorts and
// groups consistently.
static string? TruncateForColumn(string? value) =>
value is { Length: > ColumnLengths.ShortTextLength } ? value[..ColumnLengths.ShortTextLength] : value;
// an index key serving sort=message_type. This field contains a type name, so it's more useful to
// truncate from the start of the name instead of the end.
static string? TruncateTypeName(string? value) =>
value is { Length: > ColumnLengths.ShortTextLength } ? value[^ColumnLengths.ShortTextLength..] : value;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we log this as a warning?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can, but if a user reads that warning, what can they do?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if their types are this long potentially it's going to log on every single error because their namespaces are out of control everywhere.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm yeh thats true. Its something we doing that may surprise the user with no explanation. Maybe its worth something in documentation then. Also, could there be a situation where the truncation results in messages being incorrectly grouped?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a followup issue to document this somewhere


static T? GetMetadata<T>(FailedMessage.ProcessingAttempt processingAttempt, string key) =>
processingAttempt.MessageMetadata.TryGetValue(key, out var value) && value is T typed ? typed : default;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ static class FailureGroupQueries
public const int MaxGroups = 200;

/// <summary>
/// Aggregate with Title in the group key. Used by <see cref="GroupsDataStore.SingleGroup" />
/// Aggregate with Title in the group key. Used by <see cref="Implementation.GroupsDataStore.SingleGroup" />
/// where a single group is fetched and the nvarchar(max) Title cost is negligible.
/// </summary>
public static IQueryable<FailureGroupView> AggregateGroups(this IQueryable<FailedMessageGroupEntity> groups, IQueryable<FailedMessageEntity> messages) =>
Expand Down Expand Up @@ -53,8 +53,8 @@ into aggregate
/// </summary>
sealed class GroupSummary
{
public string Id { get; set; } = null!;
public string Type { get; set; } = null!;
public required string Id { get; set; }
public required string Type { get; set; }
public int Count { get; set; }
public DateTime First { get; set; }
public DateTime Last { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ public async Task An_over_length_message_type_is_capped_in_the_column_but_kept_i

using (Assert.EnterMultipleScope())
{
Assert.That(row.MessageType, Is.EqualTo(overLengthType[..450]));
Assert.That(row.MessageType!.Length, Is.EqualTo(450));
Assert.That(overLengthType.EndsWith(row.MessageType), Is.True, "the column is truncated from the start");
Assert.That(row.HeadersJson, Does.Contain(overLengthType), "the headers keep the complete type");
}
}
Expand Down