-
-
Notifications
You must be signed in to change notification settings - Fork 88
Description
Background
During the review of #490, a race condition issue was identified in the follower list management logic. See the review comment for details.
Problem
The current implementation stores follower IDs in an array under the ["followers"] key and uses a read-modify-write pattern to add or remove followers. This pattern is susceptible to race conditions when multiple activities are processed concurrently—one process can overwrite changes made by another, resulting in followers being incorrectly added or removed.
Scenario 1: Adding followers concurrently
- Process
Areads followers[A, B] - Process
Breads followers[A, B] - Process
AaddsCand writes[A, B, C] - Process
BaddsDand writes[A, B, D], overwritingA's change
Result: Follower C is lost.
Scenario 2: Removing followers concurrently
- Process
Areads followers[A, B, C] - Process
Breads followers[A, B, C] - Process
AremovesBand writes[A, C] - Process
BremovesCand writes[A, B], overwritingA's change
Result: Follower B is incorrectly restored, and C is incorrectly restored.
The affected files are:
- packages/relay/src/mastodon.ts
- packages/relay/src/litepub.ts
- packages/relay/src/follow.ts
- packages/relay/src/builder.ts
Suggested approach
Since KvStore.list() will be a required operation in Fedify 2.0.0 (#499), we can eliminate the ["followers"] array and instead rely on the list(["follower"]) operation to enumerate followers. This way, adding or removing a follower becomes a single atomic set() or delete() call on the individual ["follower", actorId] key, avoiding the race condition entirely.
Related
- refactor(relay): implement factory pattern with Mastodon and LitePub relay support #490 (PR where this issue was identified)
- Add optional
list()operation toKvStore#498 / Addlist()method toKvStoreinterface #500 (KvStore.list()implementation) - Make
KvStore.list()required in 2.0.0 #499 (KvStore.list()becomes required in 2.0.0)