diff --git a/fep/1a11/fep-1a11.md b/fep/1a11/fep-1a11.md new file mode 100644 index 0000000..a716811 --- /dev/null +++ b/fep/1a11/fep-1a11.md @@ -0,0 +1,208 @@ +--- +slug: "1a11" +authors: Rimu Atkinson +status: DRAFT +dateReceived: 2026-04-01 +discussionsTo: https://socialhub.activitypub.rocks/t/fep-1a11-send-announces-containing-many-activities/8629 +--- +# FEP-1a11: Send Announces Containing Many Activities + + +## Summary + +This proposal describes a mechanism for sending multiple activities in a single POST. The core idea is to extend FEP 1b12 slightly by changing the `object` property on `Announce` activities from an object to a list/array of objects. + +## Motivation + +Currently, ActivityPub involves sending a HTTP POST request to followers whenever something notable happens. As a user +can do a great number of notable things (posting content, liking content, following others) each minute and there can +be thousands of instances to send to, a great many POST requests can be sent in a short amount of time. + +For example if 5 people cast 20 votes and there are 500 instances, the instance hosting the community containing the +posts being voted on must send 5 * 20 * 500 = 50,000 HTTP POSTs. + +Each POST involves overhead and uses resources at both ends while it occurs. To reduce this overhead and resource use, +this proposal describes a mechanism for sending multiple activities in a single POST. + +Benefits include: decreased network traffic, higher efficiency, greater scalability, lowered carbon emissions and lower +server costs. + + +## Requirements + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this specification are to be interpreted as described in [RFC-2119]. + +For the purposes of this document, a "Origin Server" is the location where a user is logged in, and that sends the Actor's Activity. A "Remote Server" is another location on the Internet that will receive those Activities. + +## Proposal + +The majority of FEP 1b12-based ActivityPub traffic involves the transfer of an `Announce` with a up/down vote in it. This FEP only addresses those activities - all other traffic is processed in the usual way. + +Origin Servers SHOULD continue to send individual POSTs with a single Activity in them, just as they do now. For votes, +which are not especially time-sensitive, they MAY instead keep the Activity unsent in a queue. + +Origin Servers SHOULD include metadata with each queued Activity recording the community it is being sent from and the +instance it is destined for. + +Once an implementation-specific threshold is reached (e.g. a certain amount of time has passed or a queue has grown +to a certain size) the Activities from each community will be batched together under one `Announce` (per community) +and that batch federated to each destination instance. + +A batch of Activities MUST be comprised of an `Announce` that has an `object` attribute that is an `OrderedCollection` +of `Like`, `Dislike`, `Undo(Like)` or `Undo(Dislike)` activities. + +Remote Servers SHOULD process the Activities' object property serially in the order provided. + +The batch MUST be [HTTP Signed](https://docs.joinmastodon.org/spec/security/#http) by a [`Group`](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-application) actor, the community that generated the batch, which SHOULD be find-able using WebFinger. The signature SHOULD include the date the signing took place, to make replay attacks less likely. This method of signing is widely used on the Fediverse already. + +Remote Servers MAY use HTTP Signature verification to ensure the integrity of the received Activity. + + + +### POST Example + +#### Existing old-style POSTs + +``` +POST server.tld/inbox +Signature: a69F3mfddd99dGjmvjdjjs81e12jn121Gkm1 +Digest: asdfasdfasdf +{ + "actor": "https://lemmy.world/c/nostupidquestions", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "object": { + "id": "https://lemmy.world/activities/like/aa6d9456-0960-4b9d15-561d1cef2991", + "actor": "https://lemmy.world/u/SpaceNo", + "object": "https://kbin.social/m/nostupidquestions@lemmy.world/t/433370/-/comment/2965", + "type": "Like", + "audience": "https://lemmy.world/c/nostupidquestions" + }, + "cc": [ + "https://lemmy.world/c/nostupidquestions/followers" + ], + "type": "Announce", + "id": "https://lemmy.world/activities/announce/e49d182c-db32-4a10-bb-c57de890cd9e", + "@context": [ + ... + ], +} + + +POST server.tld/inbox +Signature: b69F3mfddd99dGjmvjdjjs81e12jn121Gkm1 +Digest: asdfasdfasdf +{ + "actor": "https://lemmy.world/c/nostupidquestions", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "object": { + "id": "https://lemmy.world/activities/like/aa6d9456-094bf0-9d15-561d1cef299e", + "actor": "https://lemmy.world/u/Peter", + "object": "https://kbin.social/m/nostupidquestions@lemmy.world/t/433370/-/comment/2965", + "type": "Like", + "audience": "https://lemmy.world/c/nostupidquestions" + }, + "cc": [ + "https://lemmy.world/c/nostupidquestions/followers" + ], + "type": "Announce", + "id": "https://lemmy.world/activities/announce/e49d182c-db32-4a10-bb-c57de890cd9e", + "@context": [ + ... + ], +} + + +POST server.tld/inbox +Signature: c69F3mfddd99dGjmvjdjjs81e12jn121Gkm1 +Digest: asdfasdfasdf +{ + "actor": "https://lemmy.world/c/nostupidquestions", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "object": { + "id": "https://lemmy.world/activities/like/aa6d9456-0960-4bf0-9d15-56cef2994", + "actor": "https://lemmy.world/u/Rimu", + "object": "https://kbin.social/m/nostupidquestions@lemmy.world/t/433370/-/comment/2965", + "type": "Like", + "audience": "https://lemmy.world/c/nostupidquestions" + }, + "cc": [ + "https://lemmy.world/c/nostupidquestions/followers" + ], + "type": "Announce", + "id": "https://lemmy.world/activities/announce/e49d182c-db32-4a10-bb-c57de890cd9e", + "@context": [ + ... + ], +} +``` + +#### New and improved fep-4248-style POST + +``` +POST server.tld/inbox +Signature: asdfasdfasdf +Digest: asdfasdfasdf +{ + "actor": "https://lemmy.world/c/nostupidquestions", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "object": { + "type": "OrderedCollection", + "id": "https://lemmy.world/activities/abcd9456-0960-4b9d15-561d1cef2991", + "totalItems": 3, + "orderedItems": [ + { + "id": "https://lemmy.world/activities/like/aa6d9456-0960-4b9d15-561d1cef2991", + "actor": "https://lemmy.world/u/SpaceNo", + "object": "https://kbin.social/m/nostupidquestions@lemmy.world/t/433370/-/comment/2965", + "type": "Like", + "audience": "https://lemmy.world/c/nostupidquestions" + }, + { + "id": "https://lemmy.world/activities/like/aa6d9456-094bf0-9d15-561d1cef299e", + "actor": "https://lemmy.world/u/Peter", + "object": "https://kbin.social/m/nostupidquestions@lemmy.world/t/433370/-/comment/2965", + "type": "Like", + "audience": "https://lemmy.world/c/nostupidquestions" + }, + { + "id": "https://lemmy.world/activities/like/aa6d9456-0960-4bf0-9d15-56cef2994", + "actor": "https://lemmy.world/u/Rimu", + "object": "https://kbin.social/m/nostupidquestions@lemmy.world/t/433370/-/comment/2965", + "type": "Like", + "audience": "https://lemmy.world/c/nostupidquestions" + } + ], + } + "cc": [ + "https://lemmy.world/c/nostupidquestions/followers" + ], + "type": "Announce", + "id": "https://lemmy.world/activities/announce/e49d182c-db32-4a10-bb-c57de890cd9e", + "@context": [ + ... + ], +} + +``` + +## References + +- Christine Lemmer Webber, Jessica Tallon, [ActivityPub][ActivityPub], 2018 + +[ActivityPub]: https://www.w3.org/TR/activitypub/ +[c390]: https://codeberg.org/fediverse/fep/src/branch/main/fep/c390/fep-c390.md +[RFC-2119]: https://www.rfc-editor.org/rfc/rfc2119 + +## Copyright + +CC0 1.0 Universal (CC0 1.0) Public Domain Dedication + +To the extent possible under law, the authors of this Fediverse Enhancement Proposal have waived all copyright and related or neighboring rights to this work.