[backend/core] Add instance counters (ISH-107)
This commit is contained in:
parent
ad21897928
commit
a719fc722e
6 changed files with 129 additions and 4 deletions
|
@ -88,10 +88,11 @@ public static class WebApplicationExtensions
|
||||||
|
|
||||||
if (args.Contains("--recompute-counters"))
|
if (args.Contains("--recompute-counters"))
|
||||||
{
|
{
|
||||||
app.Logger.LogInformation("Recomputing note & user counters, this will take a while...");
|
app.Logger.LogInformation("Recomputing note, user & instance counters, this will take a while...");
|
||||||
var maintenanceSvc = provider.GetRequiredService<DatabaseMaintenanceService>();
|
var maintenanceSvc = provider.GetRequiredService<DatabaseMaintenanceService>();
|
||||||
await maintenanceSvc.RecomputeNoteCountersAsync();
|
await maintenanceSvc.RecomputeNoteCountersAsync();
|
||||||
await maintenanceSvc.RecomputeUserCountersAsync();
|
await maintenanceSvc.RecomputeUserCountersAsync();
|
||||||
|
await maintenanceSvc.RecomputeInstanceCountersAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Logger.LogInformation("Verifying redis connection...");
|
app.Logger.LogInformation("Verifying redis connection...");
|
||||||
|
|
|
@ -335,6 +335,16 @@ public class ActivityHandlerService(
|
||||||
follower.FollowingCount++;
|
follower.FollowingCount++;
|
||||||
followee.FollowersCount++;
|
followee.FollowersCount++;
|
||||||
|
|
||||||
|
_ = followupTaskSvc.ExecuteTask("UpdateInstanceFollowingCounter", async provider =>
|
||||||
|
{
|
||||||
|
var bgDb = provider.GetRequiredService<DatabaseContext>();
|
||||||
|
var bgInstanceSvc = provider.GetRequiredService<InstanceService>();
|
||||||
|
var dbInstance = await bgInstanceSvc.GetUpdatedInstanceMetadataAsync(follower.Host,
|
||||||
|
new Uri(follower.Uri!).Host);
|
||||||
|
await bgDb.Instances.Where(p => p.Id == dbInstance.Id)
|
||||||
|
.ExecuteUpdateAsync(p => p.SetProperty(i => i.FollowingCount, i => i.FollowingCount + 1));
|
||||||
|
});
|
||||||
|
|
||||||
await db.AddAsync(following);
|
await db.AddAsync(following);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
await notificationSvc.GenerateFollowNotification(follower, followee);
|
await notificationSvc.GenerateFollowNotification(follower, followee);
|
||||||
|
@ -403,6 +413,16 @@ public class ActivityHandlerService(
|
||||||
actor.FollowersCount++;
|
actor.FollowersCount++;
|
||||||
request.Follower.FollowingCount++;
|
request.Follower.FollowingCount++;
|
||||||
|
|
||||||
|
_ = followupTaskSvc.ExecuteTask("UpdateInstanceFollowersCounter", async provider =>
|
||||||
|
{
|
||||||
|
var bgDb = provider.GetRequiredService<DatabaseContext>();
|
||||||
|
var bgInstanceSvc = provider.GetRequiredService<InstanceService>();
|
||||||
|
var dbInstance = await bgInstanceSvc.GetUpdatedInstanceMetadataAsync(request.Followee.Host!,
|
||||||
|
new Uri(request.Followee.Uri!).Host);
|
||||||
|
await bgDb.Instances.Where(p => p.Id == dbInstance.Id)
|
||||||
|
.ExecuteUpdateAsync(p => p.SetProperty(i => i.FollowersCount, i => i.FollowersCount + 1));
|
||||||
|
});
|
||||||
|
|
||||||
db.Remove(request);
|
db.Remove(request);
|
||||||
await db.AddAsync(following);
|
await db.AddAsync(following);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
|
@ -23,4 +23,18 @@ public class DatabaseMaintenanceService(DatabaseContext db)
|
||||||
.SetProperty(u => u.NotesCount,
|
.SetProperty(u => u.NotesCount,
|
||||||
u => db.Notes.Count(n => n.User == u && !n.IsPureRenote)));
|
u => db.Notes.Count(n => n.User == u && !n.IsPureRenote)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task RecomputeInstanceCountersAsync()
|
||||||
|
{
|
||||||
|
await db.Instances.ExecuteUpdateAsync(p => p.SetProperty(i => i.NotesCount,
|
||||||
|
i => db.Notes.Count(n => n.UserHost == i.Host))
|
||||||
|
.SetProperty(i => i.UsersCount,
|
||||||
|
i => db.Users.Count(u => u.Host == i.Host))
|
||||||
|
.SetProperty(i => i.FollowersCount,
|
||||||
|
i => db.Followings
|
||||||
|
.Count(n => n.FolloweeHost == i.Host))
|
||||||
|
.SetProperty(i => i.FollowingCount,
|
||||||
|
i => db.Followings
|
||||||
|
.Count(n => n.FollowerHost == i.Host)));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@ public class InstanceService(DatabaseContext db, HttpClient httpClient)
|
||||||
o.PoolInitialFill = 5;
|
o.PoolInitialFill = 5;
|
||||||
});
|
});
|
||||||
|
|
||||||
private async Task<Instance> GetUpdatedInstanceMetadataAsync(string host, string webDomain)
|
public async Task<Instance> GetUpdatedInstanceMetadataAsync(string host, string webDomain)
|
||||||
{
|
{
|
||||||
host = host.ToLowerInvariant();
|
host = host.ToLowerInvariant();
|
||||||
var instance = db.Instances.FirstOrDefault(p => p.Host == host);
|
var instance = db.Instances.FirstOrDefault(p => p.Host == host);
|
||||||
|
|
|
@ -37,7 +37,8 @@ public class NoteService(
|
||||||
NotificationService notificationSvc,
|
NotificationService notificationSvc,
|
||||||
EventService eventSvc,
|
EventService eventSvc,
|
||||||
ActivityPub.ActivityRenderer activityRenderer,
|
ActivityPub.ActivityRenderer activityRenderer,
|
||||||
EmojiService emojiSvc
|
EmojiService emojiSvc,
|
||||||
|
FollowupTaskService followupTaskSvc
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
private readonly List<string> _resolverHistory = [];
|
private readonly List<string> _resolverHistory = [];
|
||||||
|
@ -111,7 +112,23 @@ public class NoteService(
|
||||||
await notificationSvc.GenerateReplyNotifications(note, mentionedLocalUserIds);
|
await notificationSvc.GenerateReplyNotifications(note, mentionedLocalUserIds);
|
||||||
await notificationSvc.GenerateRenoteNotification(note);
|
await notificationSvc.GenerateRenoteNotification(note);
|
||||||
|
|
||||||
if (user.Host != null) return note;
|
if (user.Host != null)
|
||||||
|
{
|
||||||
|
if (user.Uri != null)
|
||||||
|
{
|
||||||
|
_ = followupTaskSvc.ExecuteTask("UpdateInstanceNoteCounter", async provider =>
|
||||||
|
{
|
||||||
|
var bgDb = provider.GetRequiredService<DatabaseContext>();
|
||||||
|
var bgInstanceSvc = provider.GetRequiredService<InstanceService>();
|
||||||
|
var dbInstance =
|
||||||
|
await bgInstanceSvc.GetUpdatedInstanceMetadataAsync(user.Host, new Uri(user.Uri).Host);
|
||||||
|
await bgDb.Instances.Where(p => p.Id == dbInstance.Id)
|
||||||
|
.ExecuteUpdateAsync(p => p.SetProperty(i => i.NotesCount, i => i.NotesCount + 1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return note;
|
||||||
|
}
|
||||||
|
|
||||||
var actor = userRenderer.RenderLite(user);
|
var actor = userRenderer.RenderLite(user);
|
||||||
ASActivity activity = note is { IsPureRenote: true, Renote: not null }
|
ASActivity activity = note is { IsPureRenote: true, Renote: not null }
|
||||||
|
@ -232,7 +249,22 @@ public class NoteService(
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
if (note.UserHost != null)
|
if (note.UserHost != null)
|
||||||
|
{
|
||||||
|
if (note.User.Uri != null)
|
||||||
|
{
|
||||||
|
_ = followupTaskSvc.ExecuteTask("UpdateInstanceNoteCounter", async provider =>
|
||||||
|
{
|
||||||
|
var bgDb = provider.GetRequiredService<DatabaseContext>();
|
||||||
|
var bgInstanceSvc = provider.GetRequiredService<InstanceService>();
|
||||||
|
var dbInstance =
|
||||||
|
await bgInstanceSvc.GetUpdatedInstanceMetadataAsync(note.UserHost, new Uri(note.User.Uri).Host);
|
||||||
|
await bgDb.Instances.Where(p => p.Id == dbInstance.Id)
|
||||||
|
.ExecuteUpdateAsync(p => p.SetProperty(i => i.NotesCount, i => i.NotesCount - 1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var recipients = await db.Users.Where(p => note.Mentions.Concat(note.VisibleUserIds).Distinct().Contains(p.Id))
|
var recipients = await db.Users.Where(p => note.Mentions.Concat(note.VisibleUserIds).Distinct().Contains(p.Id))
|
||||||
.Select(p => new User { Host = p.Host, Inbox = p.Inbox })
|
.Select(p => new User { Host = p.Host, Inbox = p.Inbox })
|
||||||
|
@ -279,6 +311,21 @@ public class NoteService(
|
||||||
db.Remove(dbNote);
|
db.Remove(dbNote);
|
||||||
eventSvc.RaiseNoteDeleted(this, dbNote);
|
eventSvc.RaiseNoteDeleted(this, dbNote);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
// ReSharper disable once EntityFramework.NPlusOne.IncompleteDataUsage (same reason as above)
|
||||||
|
if (dbNote.User.Uri != null && dbNote.UserHost != null)
|
||||||
|
{
|
||||||
|
_ = followupTaskSvc.ExecuteTask("UpdateInstanceNoteCounter", async provider =>
|
||||||
|
{
|
||||||
|
var bgDb = provider.GetRequiredService<DatabaseContext>();
|
||||||
|
var bgInstanceSvc = provider.GetRequiredService<InstanceService>();
|
||||||
|
// ReSharper disable once EntityFramework.NPlusOne.IncompleteDataUsage (same reason as above)
|
||||||
|
var dbInstance =
|
||||||
|
await bgInstanceSvc.GetUpdatedInstanceMetadataAsync(dbNote.UserHost, new Uri(dbNote.User.Uri).Host);
|
||||||
|
await bgDb.Instances.Where(p => p.Id == dbInstance.Id)
|
||||||
|
.ExecuteUpdateAsync(p => p.SetProperty(i => i.NotesCount, i => i.NotesCount - 1));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UndoAnnounceAsync(ASNote note, User actor)
|
public async Task UndoAnnounceAsync(ASNote note, User actor)
|
||||||
|
|
|
@ -185,6 +185,14 @@ public class UserService(
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
await processPendingDeletes();
|
await processPendingDeletes();
|
||||||
user = await UpdateProfileMentions(user, actor);
|
user = await UpdateProfileMentions(user, actor);
|
||||||
|
_ = followupTaskSvc.ExecuteTask("UpdateInstanceUserCounter", async provider =>
|
||||||
|
{
|
||||||
|
var bgDb = provider.GetRequiredService<DatabaseContext>();
|
||||||
|
var bgInstanceSvc = provider.GetRequiredService<InstanceService>();
|
||||||
|
var dbInstance = await bgInstanceSvc.GetUpdatedInstanceMetadataAsync(host, new Uri(uri).Host);
|
||||||
|
await bgDb.Instances.Where(p => p.Id == dbInstance.Id)
|
||||||
|
.ExecuteUpdateAsync(p => p.SetProperty(i => i.UsersCount, i => i.UsersCount + 1));
|
||||||
|
});
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
catch (UniqueConstraintException)
|
catch (UniqueConstraintException)
|
||||||
|
@ -437,6 +445,15 @@ public class UserService(
|
||||||
db.Remove(user);
|
db.Remove(user);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
_ = followupTaskSvc.ExecuteTask("UpdateInstanceUserCounter", async provider =>
|
||||||
|
{
|
||||||
|
var bgDb = provider.GetRequiredService<DatabaseContext>();
|
||||||
|
var bgInstanceSvc = provider.GetRequiredService<InstanceService>();
|
||||||
|
var dbInstance = await bgInstanceSvc.GetUpdatedInstanceMetadataAsync(user.Host!, new Uri(user.Uri!).Host);
|
||||||
|
await bgDb.Instances.Where(p => p.Id == dbInstance.Id)
|
||||||
|
.ExecuteUpdateAsync(p => p.SetProperty(i => i.UsersCount, i => i.UsersCount - 1));
|
||||||
|
});
|
||||||
|
|
||||||
if (user.Avatar != null)
|
if (user.Avatar != null)
|
||||||
await driveSvc.RemoveFile(user.Avatar);
|
await driveSvc.RemoveFile(user.Avatar);
|
||||||
if (user.Banner != null)
|
if (user.Banner != null)
|
||||||
|
@ -511,6 +528,19 @@ public class UserService(
|
||||||
await db.AddAsync(following);
|
await db.AddAsync(following);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
if (request.Follower is { Host: not null })
|
||||||
|
{
|
||||||
|
_ = followupTaskSvc.ExecuteTask("UpdateInstanceFollowingCounter", async provider =>
|
||||||
|
{
|
||||||
|
var bgDb = provider.GetRequiredService<DatabaseContext>();
|
||||||
|
var bgInstanceSvc = provider.GetRequiredService<InstanceService>();
|
||||||
|
var dbInstance = await bgInstanceSvc.GetUpdatedInstanceMetadataAsync(request.Follower.Host,
|
||||||
|
new Uri(request.Follower.Uri!).Host);
|
||||||
|
await bgDb.Instances.Where(p => p.Id == dbInstance.Id)
|
||||||
|
.ExecuteUpdateAsync(p => p.SetProperty(i => i.FollowingCount, i => i.FollowingCount + 1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await notificationSvc.GenerateFollowNotification(request.Follower, request.Followee);
|
await notificationSvc.GenerateFollowNotification(request.Follower, request.Followee);
|
||||||
await notificationSvc.GenerateFollowRequestAcceptedNotification(request);
|
await notificationSvc.GenerateFollowRequestAcceptedNotification(request);
|
||||||
|
|
||||||
|
@ -627,6 +657,19 @@ public class UserService(
|
||||||
db.RemoveRange(followings);
|
db.RemoveRange(followings);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
if (followee.Host != null)
|
||||||
|
{
|
||||||
|
_ = followupTaskSvc.ExecuteTask("UpdateInstanceFollowersCounter", async provider =>
|
||||||
|
{
|
||||||
|
var bgDb = provider.GetRequiredService<DatabaseContext>();
|
||||||
|
var bgInstanceSvc = provider.GetRequiredService<InstanceService>();
|
||||||
|
var dbInstance =
|
||||||
|
await bgInstanceSvc.GetUpdatedInstanceMetadataAsync(followee.Host, new Uri(followee.Uri!).Host);
|
||||||
|
await bgDb.Instances.Where(p => p.Id == dbInstance.Id)
|
||||||
|
.ExecuteUpdateAsync(p => p.SetProperty(i => i.FollowersCount, i => i.FollowersCount - 1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
followee.PrecomputedIsFollowedBy = false;
|
followee.PrecomputedIsFollowedBy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue