Skip to content

Commit f3ec0e5

Browse files
authored
Add another truncation case (microsoft#3075)
* Add another truncation case * fmt
1 parent 16ebd2d commit f3ec0e5

File tree

4 files changed

+67
-30
lines changed

4 files changed

+67
-30
lines changed

src/ApiService/ApiService/OneFuzzTypes/Events.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,14 +348,25 @@ public record EventNotificationFailed(
348348
Error? Error
349349
) : BaseEvent();
350350

351-
public record DownloadableEventMessage : EventMessage {
351+
public record DownloadableEventMessage : EventMessage, ITruncatable<DownloadableEventMessage> {
352352
public Uri SasUrl { get; init; }
353353

354354
public DownloadableEventMessage(Guid EventId, EventType EventType, BaseEvent Event, Guid InstanceId, string InstanceName, DateTime CreatedAt, Uri SasUrl)
355355
: base(EventId, EventType, Event, InstanceId, InstanceName, CreatedAt) {
356356
this.SasUrl = SasUrl;
357357
}
358+
359+
public override DownloadableEventMessage Truncate(int maxLength) {
360+
if (this.Event is ITruncatable<BaseEvent> truncatableEvent) {
361+
return this with {
362+
Event = truncatableEvent.Truncate(maxLength)
363+
};
364+
} else {
365+
return this;
366+
}
367+
}
358368
}
369+
359370
public record EventMessage(
360371
Guid EventId,
361372
EventType EventType,
@@ -366,7 +377,17 @@ public record EventMessage(
366377
String InstanceName,
367378
DateTime CreatedAt,
368379
String Version = "1.0"
369-
);
380+
) : ITruncatable<EventMessage> {
381+
public virtual EventMessage Truncate(int maxLength) {
382+
if (this.Event is ITruncatable<BaseEvent> truncatableEvent) {
383+
return this with {
384+
Event = truncatableEvent.Truncate(maxLength)
385+
};
386+
} else {
387+
return this;
388+
}
389+
}
390+
}
370391

371392
public class BaseEventConverter : JsonConverter<BaseEvent> {
372393
public override BaseEvent? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {

src/ApiService/ApiService/onefuzzlib/Events.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@ public record SignalREvent
1111
(
1212
string Target,
1313
List<DownloadableEventMessage> arguments
14-
);
15-
14+
) : ITruncatable<SignalREvent> {
15+
public SignalREvent Truncate(int maxLength) {
16+
return this with {
17+
arguments = arguments.Select(x => x.Truncate(maxLength)).ToList()
18+
};
19+
}
20+
}
1621

1722
public interface IEvents {
1823
Async.Task SendEvent(BaseEvent anEvent);
@@ -47,8 +52,16 @@ public Events(ILogTracer log, IOnefuzzContext context) {
4752
}
4853

4954
public virtual async Async.Task QueueSignalrEvent(DownloadableEventMessage message) {
55+
var tags = new (string, string)[] {
56+
("event_type", message.EventType.ToString()),
57+
("event_id", message.EventId.ToString())
58+
};
5059
var ev = new SignalREvent("events", new List<DownloadableEventMessage>() { message });
51-
await _queue.SendMessage("signalr-events", JsonSerializer.Serialize(ev, _options), StorageType.Config);
60+
var queueResult = await _queue.QueueObject("signalr-events", ev, StorageType.Config, serializerOptions: _options);
61+
62+
if (!queueResult) {
63+
_log.WithTags(tags).Error($"Fsailed to queue signalr event");
64+
}
5265
}
5366

5467
public async Async.Task SendEvent(BaseEvent anEvent) {

src/ApiService/ApiService/onefuzzlib/Queue.cs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
namespace Microsoft.OneFuzz.Service;
1111
public interface IQueue {
1212
Async.Task SendMessage(string name, string message, StorageType storageType, TimeSpan? visibilityTimeout = null, TimeSpan? timeToLive = null);
13-
Async.Task<bool> QueueObject<T>(string name, T obj, StorageType storageType, TimeSpan? visibilityTimeout = null, TimeSpan? timeToLive = null);
13+
Async.Task<bool> QueueObject<T>(string name, T obj, StorageType storageType, TimeSpan? visibilityTimeout = null, TimeSpan? timeToLive = null, JsonSerializerOptions? serializerOptions = null);
1414
Task<Uri> GetQueueSas(string name, StorageType storageType, QueueSasPermissions permissions, TimeSpan? duration = null);
1515
ResourceIdentifier GetResourceId(string queueName, StorageType storageType);
1616
Task<IList<T>> PeekQueue<T>(string name, StorageType storageType);
@@ -57,23 +57,40 @@ public async Task<QueueClient> GetQueueClient(string name, StorageType storageTy
5757
public Task<QueueServiceClient> GetQueueClientService(StorageType storageType)
5858
=> _storage.GetQueueServiceClientForAccount(_storage.GetPrimaryAccount(storageType));
5959

60-
public async Task<bool> QueueObject<T>(string name, T obj, StorageType storageType, TimeSpan? visibilityTimeout = null, TimeSpan? timeToLive = null) {
60+
public async Task<bool> QueueObject<T>(string name, T obj, StorageType storageType, TimeSpan? visibilityTimeout = null, TimeSpan? timeToLive = null, JsonSerializerOptions? serializerOptions = null) {
6161
var queueClient = await GetQueueClient(name, storageType);
62+
serializerOptions ??= EntityConverter.GetJsonSerializerOptions();
6263
try {
63-
var serialized = JsonSerializer.Serialize(obj, EntityConverter.GetJsonSerializerOptions());
64-
var res = await queueClient.SendMessageAsync(serialized, visibilityTimeout: visibilityTimeout, timeToLive);
65-
if (res.GetRawResponse().IsError) {
66-
_log.Error($"Failed to send {serialized:Tag:Message} in {name:Tag:QueueName} due to {res.GetRawResponse().ReasonPhrase:Tag:Error}");
67-
return false;
68-
} else {
69-
return true;
70-
}
64+
return await QueueObjectInternal(obj, queueClient, serializerOptions, visibilityTimeout, timeToLive);
7165
} catch (Exception ex) {
7266
_log.Exception(ex, $"Failed to queue message in {name:Tag:QueueName}");
67+
if (IsMessageTooLargeException(ex) &&
68+
obj is ITruncatable<T> truncatable) {
69+
obj = truncatable.Truncate(1000);
70+
try {
71+
return await QueueObjectInternal(obj, queueClient, serializerOptions, visibilityTimeout, timeToLive);
72+
} catch (Exception ex2) {
73+
_log.Exception(ex2, $"Failed to queue message in {name:Tag:QueueName} after truncation");
74+
}
75+
}
7376
return false;
7477
}
7578
}
7679

80+
private async Task<bool> QueueObjectInternal<T>(T obj, QueueClient queueClient, JsonSerializerOptions serializerOptions, TimeSpan? visibilityTimeout = null, TimeSpan? timeToLive = null) {
81+
var serialized = JsonSerializer.Serialize(obj, serializerOptions);
82+
var res = await queueClient.SendMessageAsync(serialized, visibilityTimeout: visibilityTimeout, timeToLive);
83+
if (res.GetRawResponse().IsError) {
84+
_log.Error($"Failed to send {serialized:Tag:Message} in {queueClient.Name:Tag:QueueName} due to {res.GetRawResponse().ReasonPhrase:Tag:Error}");
85+
return false;
86+
} else {
87+
return true;
88+
}
89+
}
90+
91+
private static bool IsMessageTooLargeException(Exception ex) =>
92+
ex is RequestFailedException rfe && rfe.Message.Contains("The request body is too large");
93+
7794
public async Task<Uri> GetQueueSas(string name, StorageType storageType, QueueSasPermissions permissions, TimeSpan? duration) {
7895
var queueClient = await GetQueueClient(name, storageType);
7996
var now = DateTimeOffset.UtcNow;

src/ApiService/ApiService/onefuzzlib/WebhookOperations.cs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Text.Json;
55
using System.Threading.Tasks;
66
using ApiService.OneFuzzLib.Orm;
7-
using Azure;
87
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;
98

109
namespace Microsoft.OneFuzz.Service;
@@ -61,20 +60,7 @@ private async Async.Task AddEvent(Webhook webhook, DownloadableEventMessage even
6160
}
6261
}
6362

64-
try {
65-
await _context.WebhookMessageLogOperations.QueueWebhook(message);
66-
} catch (RequestFailedException ex) {
67-
if (ex.Message.Contains("The request body is too large") && eventMessage.Event is ITruncatable<BaseEvent> truncatableEvent) {
68-
_logTracer.WithTags(tags).Warning($"The WebhookMessageLog was too long for Azure Queue. Truncating event data and trying again.");
69-
message = message with {
70-
Event = truncatableEvent.Truncate(1000)
71-
};
72-
await _context.WebhookMessageLogOperations.QueueWebhook(message);
73-
} else {
74-
// Not handled
75-
throw ex;
76-
}
77-
}
63+
await _context.WebhookMessageLogOperations.QueueWebhook(message);
7864
}
7965

8066
public async Async.Task<OneFuzzResultVoid> Send(WebhookMessageLog messageLog) {

0 commit comments

Comments
 (0)