FEP-8fcf rests for two weeks after a restore
What a restore lost of either side is not the other server's to mend: for RestoreRecord.FollowersGrace (14 days) deliveries carry no Collection-Synchronization header, and a follow only the remote remembers is adopted rather than undone. Without a restore nothing changes; the interop sweep (gts, mastodon, misskey, sharkey, akkoma, pixelfed, smithereen, followsync, pins, moves) passed, Smithereen's poll check on a second run. 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
bc5f2beaf7
commit
9ad96f560d
3 files changed
+21
-4
No files matched your search
@@ -525,7 +525,9 @@ group www-data and reaches the private mongod; `sudo -u www-data` works too.
|
|||||||
Each attempt redoes everything. Refused before anything changed, it is abandoned and recorded, and the server boots as
|
Each attempt redoes everything. Refused before anything changed, it is abandoned and recorded, and the server boots as
|
||||||
it was; failed midway, the process exits 1 and the next start tries again; after 3 failures it exits 75, which the
|
it was; failed midway, the process exits 1 and the next start tries again; after 3 failures it exits 75, which the
|
||||||
unit's `RestartPreventExitStatus` leaves down for someone to look. While `restore.json` exists, commands exit 75 (but
|
unit's `RestartPreventExitStatus` leaves down for someone to look. While `restore.json` exists, commands exit 75 (but
|
||||||
`admin restore --status`) and the deploy refuses to run.
|
`admin restore --status`) and the deploy refuses to run. For `RestoreRecord.FollowersGrace` (14 days) after a restore,
|
||||||
|
FEP-8fcf rests: no `Collection-Synchronization` header goes out, and a follow only the remote remembers is adopted,
|
||||||
|
not undone.
|
||||||
- **The administrator's page** (`BackupController`, `/clientapi/admin/backups`; owner decision 2026-10-07, which approved
|
- **The administrator's page** (`BackupController`, `/clientapi/admin/backups`; owner decision 2026-10-07, which approved
|
||||||
these endpoints in production): the list (with what runs, the restore waiting, the last restore's report, logins
|
these endpoints in production): the list (with what runs, the restore waiting, the last restore's report, logins
|
||||||
deleted since each backup), back up now (202; the page polls), delete, and:
|
deleted since each backup), back up now (202; the page polls), delete, and:
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ namespace PrivaPub.Federation.Actors
|
|||||||
// FEP-8fcf, received: an account elsewhere tells, with its delivery, a digest of its followers here. When the personas
|
// FEP-8fcf, received: an account elsewhere tells, with its delivery, a digest of its followers here. When the personas
|
||||||
// following it here digest otherwise, its partial list (read signed by the instance actor) says who they are: a follow
|
// following it here digest otherwise, its partial list (read signed by the instance actor) says who they are: a follow
|
||||||
// only PrivaPub remembers ends, a request it answered without our knowing is accepted, and a follow only it remembers
|
// only PrivaPub remembers ends, a request it answered without our knowing is accepted, and a follow only it remembers
|
||||||
// is undone by the persona, as Mastodon does. A follow ends only when the list is the one the digest describes.
|
// is undone by the persona, as Mastodon does, or kept within RestoreRecord.FollowersGrace of a restore, which may have
|
||||||
|
// lost it. A follow ends only when the list is the one the digest describes.
|
||||||
public class FollowingSynchronization : IJobHandler
|
public class FollowingSynchronization : IJobHandler
|
||||||
{
|
{
|
||||||
const int MaxPages = 10;
|
const int MaxPages = 10;
|
||||||
@@ -87,6 +88,19 @@ namespace PrivaPub.Federation.Actors
|
|||||||
}
|
}
|
||||||
if (await _localActors.FindByUri(uri, token) is not { Kind: LocalActorKind.Person } stranger)
|
if (await _localActors.FindByUri(uri, token) is not { Kind: LocalActorKind.Person } stranger)
|
||||||
continue;
|
continue;
|
||||||
|
// a follow the restore lost: kept, not undone
|
||||||
|
if (await Infrastructure.Backup.RestoreRecord.InFollowersGrace(token))
|
||||||
|
{
|
||||||
|
await DB.Default.SaveAsync(new Following
|
||||||
|
{
|
||||||
|
AvatarId = stranger.Id,
|
||||||
|
TargetActorURI = actor.ActorURI,
|
||||||
|
TargetAccountId = actor.ID,
|
||||||
|
TargetInboxURL = string.IsNullOrEmpty(actor.InboxURL) ? actor.SharedInboxURL : actor.InboxURL,
|
||||||
|
State = FollowState.Accepted
|
||||||
|
}, token);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// (it has no id for a follow PrivaPub never made; it is undone by actor and object)
|
// (it has no id for a follow PrivaPub never made; it is undone by actor and object)
|
||||||
var undo = new JsonObject
|
var undo = new JsonObject
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -188,10 +188,11 @@ namespace PrivaPub.Federation.Outbox
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// FEP-8fcf: what a delivery to the persona's followers tells the receiving server of its followers there
|
// FEP-8fcf: what a delivery to the persona's followers tells the receiving server of its followers there; nothing for
|
||||||
|
// a while after a restore, whose losses are not the other server's to mend
|
||||||
static async Task<(string, string)[]> Synchronization(LocalActor signer, string body, Uri inbox, CancellationToken token)
|
static async Task<(string, string)[]> Synchronization(LocalActor signer, string body, Uri inbox, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (!FollowersSynchronization.Synchronizes(signer) || JsonNode.Parse(body) is not JsonObject activity || !FollowersSynchronization.ForFollowers(activity, signer))
|
if (!FollowersSynchronization.Synchronizes(signer) || await Infrastructure.Backup.RestoreRecord.InFollowersGrace(token) || JsonNode.Parse(body) is not JsonObject activity || !FollowersSynchronization.ForFollowers(activity, signer))
|
||||||
return [];
|
return [];
|
||||||
var there = await FollowersSynchronization.On(signer, FollowersSynchronization.Origin(inbox.AbsoluteUri), token);
|
var there = await FollowersSynchronization.On(signer, FollowersSynchronization.Origin(inbox.AbsoluteUri), token);
|
||||||
return [(FollowersSynchronization.Header, FollowersSynchronization.HeaderValue(signer, FollowersSynchronization.Digest(there)))];
|
return [(FollowersSynchronization.Header, FollowersSynchronization.HeaderValue(signer, FollowersSynchronization.Digest(there)))];
|
||||||
|
|||||||
Reference in new issue
Block a user