[backend/masto-client] Fix slow notifications endpoint response time

This commit is contained in:
Laura Hausmann 2025-03-23 13:31:42 +01:00
parent f1a1ed9039
commit 1af21062fb
No known key found for this signature in database
GPG key ID: D044E84C5BE01605

View file

@ -5,6 +5,7 @@ using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Database.Tables; using Iceshrimp.Backend.Core.Database.Tables;
using Iceshrimp.Backend.Core.Extensions; using Iceshrimp.Backend.Core.Extensions;
using Iceshrimp.Backend.Core.Services; using Iceshrimp.Backend.Core.Services;
using Iceshrimp.EntityFrameworkCore.Extensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -28,13 +29,13 @@ public class NotificationRenderer(
var targetNote = notification.Note; var targetNote = notification.Note;
var note = targetNote != null var note = targetNote != null
? statuses?.FirstOrDefault(p => p.Id == targetNote.Id) ?? ? statuses?.FirstOrDefault(p => p.Id == targetNote.Id)
await noteRenderer.RenderAsync(targetNote, user, Filter.FilterContext.Notifications, ?? await noteRenderer.RenderAsync(targetNote, user, Filter.FilterContext.Notifications,
new NoteRenderer.NoteRendererDto { Accounts = accounts }) new NoteRenderer.NoteRendererDto { Accounts = accounts })
: null; : null;
var notifier = accounts?.FirstOrDefault(p => p.Id == dbNotifier.Id) ?? var notifier = accounts?.FirstOrDefault(p => p.Id == dbNotifier.Id)
await userRenderer.RenderAsync(dbNotifier, user); ?? await userRenderer.RenderAsync(dbNotifier, user);
string? emojiUrl = null; string? emojiUrl = null;
if (notification.Reaction != null) if (notification.Reaction != null)
@ -63,7 +64,9 @@ public class NotificationRenderer(
CreatedAt = notification.CreatedAt.ToStringIso8601Like(), CreatedAt = notification.CreatedAt.ToStringIso8601Like(),
Emoji = notification.Reaction, Emoji = notification.Reaction,
EmojiUrl = emojiUrl, EmojiUrl = emojiUrl,
Pleroma = flags.IsPleroma.Value ? new PleromaNotificationExtensions { IsSeen = notification.IsRead } : null Pleroma = flags.IsPleroma.Value
? new PleromaNotificationExtensions { IsSeen = notification.IsRead }
: null
}; };
return res; return res;
@ -98,27 +101,28 @@ public class NotificationRenderer(
.Select(p => .Select(p =>
{ {
var parts = p.Reaction!.Trim(':').Split('@'); var parts = p.Reaction!.Trim(':').Split('@');
return new { Name = parts[0], Host = parts.Length > 1 ? parts[1] : null }; return (name: parts[0], host: parts.Length > 1 ? parts[1] : null);
}); })
.Distinct()
.ToArray();
var expr = ExpressionExtensions.False<Emoji>();
expr = parts.Aggregate(expr, (current, part) => current.Or(p => p.Name == part.name && p.Host == part.host));
// https://github.com/dotnet/efcore/issues/31492 // https://github.com/dotnet/efcore/issues/31492
//TODO: is there a better way of expressing this using LINQ? var emojiUrls = await db.Emojis
IQueryable<Emoji> urlQ = db.Emojis; .Where(expr)
foreach (var part in parts) .Select(e => new
urlQ = urlQ.Concat(db.Emojis.Where(e => e.Name == part.Name && e.Host == part.Host)); {
Name = $":{e.Name}{(e.Host != null ? "@" + e.Host : "")}:",
Url = e.GetAccessUrl(instance.Value)
})
.ToDictionaryAsync(e => e.Name, e => e.Url);
//TODO: can we somehow optimize this to do the dedupe database side? var res = await notificationList
var emojiUrls = await urlQ.Select(e => new .Select(p => RenderAsync(p, user, isPleroma, accounts, notes, emojiUrls))
{ .AwaitAllAsync();
Name = $":{e.Name}{(e.Host != null ? "@" + e.Host : "")}:",
Url = e.GetAccessUrl(instance.Value)
})
.ToArrayAsync()
.ContinueWithResult(res => res.DistinctBy(e => e.Name)
.ToDictionary(e => e.Name, e => e.Url));
return await notificationList return res;
.Select(p => RenderAsync(p, user, isPleroma, accounts, notes, emojiUrls))
.AwaitAllAsync();
} }
} }