Add CollaborativeEditing::DocumentStore and prepare rate limit
What does this MR do and why?
Adds Gitlab::CollaborativeEditing::DocumentStore, which holds the Yjs update log for one collaboratively edited document in Gitlab::Redis::SharedState.
Updates are opaque base64 blobs. The server never decodes or merges them. Yjs updates are commutative and idempotent, so a client that applies the whole log in any order converges on the same document. Keeping CRDT logic out of Ruby is deliberate — an earlier attempt used Rust bindings for a Ruby-side CRDT and proved unsustainable to maintain.
The log is ephemeral. It lets a late joiner catch up and survives all clients briefly disconnecting. The durable copy of a wiki page is still the Git commit written on save.
Public methods:
#updates—lrangethe whole log.#append—rpushand refresh expiry. Returnstrueonce the log hitsCOMPACTION_THRESHOLD, so the caller can ask a client for a snapshot.#replace—delplusrpushof a compacted snapshot.#claim_seed— RedisSET NXwith a TTL, electing one client to write the initial document.
TTL is 1 hour, refreshed on every write, so a document expires only once editing stops. COMPACTION_THRESHOLD is 500. SEED_CLAIM_TTL is 30 seconds. Keys are hash-tagged (collaborative_editing:{<document_key>}:updates and :seed) to pin both keys for a document to one Redis Cluster slot.
Also registers a collaborative_editing_update rate limit: 600 per minute, characteristics [user, document_key]. Keying on the user and document in Redis, rather than on a channel instance, stops a user multiplying their allowance by opening extra subscriptions to the same document. It has no call site — the channel that consumes it lands in slice 3, so slice 3 stays purely the channel.
Nothing here is reachable by a user. No channel, no feature flag, no caller. DocumentStore is not instantiated anywhere yet.
Part of a split
Slice 2 of 6, split out of !250607 (closed) at this review comment.
- Slice 1 (merged): !251691 (merged) — optional
collaborationProviderthreaded into ContentEditor. - Slice 3:
CollaborativeEditing::BaseChannelandWikiPageChannel— AppSec review goes here. - Slice 4: the
ActionCableProviderimplementation. - Slice 5: wiki wiring,
CollaboratorsIndicator, and the feature flag that makes the feature reachable.
Testing
- 10 new examples in
spec/lib/gitlab/collaborative_editing/document_store_spec.rb. - 23 existing examples in
supported_rate_limits_spec.rbstill pass. - 118 existing examples across
application_rate_limiter_spec.rbandlabkit_adapter_spec.rbstill pass. - RuboCop clean on all three files.
No manual validation steps: nothing in this MR is reachable by a user.
References
- Original unsplit MR: !250607 (closed)
- Review comment requesting the split: !250607 (comment 3708895581)
- Slice 1: !251691 (merged)
- Feature work item: #14367
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.