Follow requests nobody answers are sent again
A Follow was resent only when the persona followed again. Lemmy 1.0 sends nothing it queued for a server before it started sending there, so the Accept of a community follow made on first contact was lost for good: the village's persona stayed "requested" a day while Lemmy listed her as a follower, and every post the community announced was refused as not followed. A request still unanswered is now sent again, the same activity, after 15 minutes, an hour, 6 hours, a day, two and four days (FollowResender, every 15 minutes); a server that holds the follow answers the copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
7e37f56db6
commit
01808fa644
7 files changed
+103
-2
No files matched your search
@@ -0,0 +1,27 @@
|
||||
namespace PrivaPub.Domain.Social
|
||||
{
|
||||
// sends again, now and then, the follow requests still unanswered (FollowService.ResendPending)
|
||||
public sealed class FollowResender(IServiceScopeFactory scopes, ILogger<FollowResender> logger) : BackgroundService
|
||||
{
|
||||
static readonly TimeSpan Every = TimeSpan.FromMinutes(15);
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken token)
|
||||
{
|
||||
using var timer = new PeriodicTimer(Every);
|
||||
while (await timer.WaitForNextTickAsync(token))
|
||||
{
|
||||
try
|
||||
{
|
||||
using var scope = scopes.CreateScope();
|
||||
var sent = await scope.ServiceProvider.GetRequiredService<IFollowService>().ResendPending(DateTime.UtcNow, token);
|
||||
if (sent > 0)
|
||||
logger.LogInformation("Sent {Count} unanswered follow requests again", sent);
|
||||
}
|
||||
catch (Exception ex) when (ex is not OperationCanceledException)
|
||||
{
|
||||
logger.LogWarning(ex, "Unanswered follow requests could not be sent again");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ namespace PrivaPub.Domain.Social
|
||||
Task<Following> FollowAs(LocalActor follower, string target, bool showReblogs, CancellationToken token);
|
||||
Task UnfollowAs(LocalActor follower, string target, CancellationToken token);
|
||||
Task<bool> Decide(LocalActor me, string followerAccountId, bool accept, CancellationToken token);
|
||||
Task<int> ResendPending(DateTime now, CancellationToken token);
|
||||
}
|
||||
|
||||
public class FollowService : IFollowService
|
||||
@@ -276,6 +277,37 @@ namespace PrivaPub.Domain.Social
|
||||
return (default, actorUri == default ? default : await _remoteActors.GetActor(actorUri, refresh: false, token));
|
||||
}
|
||||
|
||||
// how long after it was made, or last sent again, a request still unanswered is sent again: a server can take a Follow and
|
||||
// lose its answer (Lemmy 1.0 sends nothing it queued for a server before it started sending there), and one that
|
||||
// already holds the follow answers the copy again
|
||||
public static readonly TimeSpan[] ResendAfter =
|
||||
{
|
||||
TimeSpan.FromMinutes(15), TimeSpan.FromHours(1), TimeSpan.FromHours(6), TimeSpan.FromDays(1), TimeSpan.FromDays(2), TimeSpan.FromDays(4)
|
||||
};
|
||||
|
||||
// the requests to remote accounts due to be sent again; how many were
|
||||
public async Task<int> ResendPending(DateTime now, CancellationToken token)
|
||||
{
|
||||
var sent = 0;
|
||||
// (a request older than the count has no Resent yet: "not at least" matches it, "less than" would not)
|
||||
var pending = await _dbEntities.Followings.Match(f => f.State == FollowState.Requested && !f.TargetIsLocal && !(f.Resent >= ResendAfter.Length))
|
||||
.ExecuteAsync(token);
|
||||
foreach (var following in pending.Where(f => (f.ResentAt ?? f.CreatedAt) + ResendAfter[f.Resent] <= now))
|
||||
{
|
||||
var follower = await _localActors.FindById(LocalActorKind.Person, following.AvatarId, token);
|
||||
var inbox = following.TargetInboxURL ?? (await _remoteActors.GetActor(following.TargetActorURI, refresh: false, token))?.InboxURL;
|
||||
if (follower != default && !string.IsNullOrEmpty(inbox))
|
||||
{
|
||||
await _delivery.Enqueue(follower, new[] { inbox }, FollowActivity(follower, following), token,
|
||||
again: "resend-" + now.ToString("yyyyMMddHHmm", System.Globalization.CultureInfo.InvariantCulture));
|
||||
sent++;
|
||||
}
|
||||
await DB.Default.Update<Following>().MatchID(following.ID).Modify(b => b.Inc(f => f.Resent, 1)).Modify(f => f.ResentAt, now)
|
||||
.ExecuteAsync(token);
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
static JsonObject FollowActivity(LocalActor follower, Following following) => new()
|
||||
{
|
||||
["@context"] = ActivityPubRenderer.ActivityStreams,
|
||||
|
||||
Reference in new issue
Block a user