Move rate-limit-manager to messaging client layer#4021
Open
stubbsta wants to merge 3 commits into
Open
Conversation
|
You can find the image built from this PR at Built from 07c79ef |
stubbsta
force-pushed
the
chore/move-ratelimitmanager-to-client-layer
branch
4 times, most recently
from
July 16, 2026 08:05
f4f21ba to
c1d4040
Compare
stubbsta
marked this pull request as ready for review
July 16, 2026 12:26
stubbsta
requested review from
Ivansete-status,
NagyZoltanPeter,
darshankabariya and
fcecin
July 16, 2026 12:26
stubbsta
force-pushed
the
chore/move-ratelimitmanager-to-client-layer
branch
from
July 16, 2026 12:40
c1d4040 to
9bf7e57
Compare
Collapses the outgoing pipeline to `segmentation -> sds -> encryption -> dispatch` by folding the encrypt-and-dispatch tail of `onReadyToSend` directly into `send()`. Removes the `RateLimitManager` field, its constructor param, the `ReadyToSendEvent` listener, and the `awaitingDispatch` accounting that only existed to bridge the event-bus hop between `send()` and `onReadyToSend`. The `rate_limit_manager.nim` module itself is untouched — it will be relocated to the messaging layer (co-located with RLN) in a follow-up commit, where per-epoch admission actually belongs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Moves rate_limit_manager.nim from `logos_delivery/channels/` to `logos_delivery/messaging/rate_limit_manager/` — the correct owner now that admission sits alongside RLN in the messaging layer instead of being fanned out to per-channel event listeners. The API surface changes: - `enqueueToSend` + `ReadyToSendEvent` (broker-based fan-out to a ReliableChannel listener) is replaced by `admit(msg): Future[Result[ void, RateLimitError]]`. Callers now branch directly on the result instead of subscribing to an event. - `channelId`, `SdsChannelID` and the SDS import are dropped — the messaging layer has no notion of channels; SDS was a channels-layer concern that only survived on this type because of the old broker fan-out. - `brokerCtx` is dropped for the same reason. Epoch config (`epochPeriodSec`), the wall-clock `currentEpochStart`, `queue`, `dequeueReady`, and `resetEpoch` are preserved exactly as the original owner designed them — this refactor is intentionally scoped to the API surface, not the epoch mechanism. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires the relocated RateLimitManager into the messaging layer at the transmission stage rather than the API entry point: - MessagingClientConf gains a rateLimit: RateLimitConfig field (defaulting to DefaultEpochPeriodSec / DefaultMessagesPerEpoch), and MessagingClient.new hands the constructed manager to SendService. - SendService consults admit() before the first transmission of a task, both in send() and in the retry loop. Re-publishes of an already-propagated message (firstPropagatedTime set) skip admission: they resend the same bytes, which reuse the same RLN proof/nullifier and consume no fresh epoch slot. - An over-budget task parks in the task cache as NextRoundRetry; the service loop re-admits it as the epoch budget frees up. The skeleton admit() is a pass-through, so behaviour is unchanged today. Gating transmissions instead of MessagingClient.send keeps SDS repair rebroadcasts free of API-entry rejection (SDS decides that a repair is needed; the transmission scheduler decides when it fits the budget) while every wire transmission still draws from one node-wide budget -- which network-side RLN enforcement applies to repairs regardless of any local bypass. It is also where RLN proof attachment must happen, since proofs bind to the epoch current at transmission time. Adds tests/messaging/test_rate_limit_manager.nim covering the current disabled + enabled pass-through behaviour, wired into all_tests_waku.nim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
stubbsta
force-pushed
the
chore/move-ratelimitmanager-to-client-layer
branch
from
July 17, 2026 11:27
9bf7e57 to
c7f767d
Compare
Ivansete-status
approved these changes
Jul 17, 2026
Ivansete-status
left a comment
Collaborator
There was a problem hiding this comment.
Great movement! Thanks! 🙌
| ## Spec-level entry point. Looks the channel up by id and delegates | ||
| ## to `ReliableChannel.send`, which exposes the visible pipeline | ||
| ## segmentation -> sds -> rate_limit_manager -> encryption. | ||
| ## segmentation -> sds -> encryption -> dispatch. |
Collaborator
There was a problem hiding this comment.
Suggested change
| ## segmentation -> sds -> encryption -> dispatch. | |
| ## segmentation -> sds -> encryption -> rate_limit_manager. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Moves
rate_limit_managerout of the reliable-channels layer into themessaging layer, so it sits next to the send pipeline and (in follow-up
work) can interact directly with the RLN component. Three commits, each
reviewable on its own:
1. Drop the rate-limit stage from the reliable channel pipeline
The outgoing pipeline collapses to
segmentation → sds → encryption → dispatch. Since the rate-limit hop was the only reason encrypt anddispatch were decoupled through the event bus, the encrypt-and-dispatch
tail of
onReadyToSendfolds back intosend(), and with it goes allthe machinery that existed only to bridge that hop:
rateLimitfield andrateConfigconstructor param onReliableChannel(and all call sites, incl. the channel manager),ReadyToSendEventlistener and the event type (no other producer),awaitingDispatchaccounting,enqueueToSendon the manager.reliable_channel.nimis −191 lines net; the channels layer no longerreferences rate limiting at all.
2. Relocate the module to
logos_delivery/messaging/rate_limit_manager/The move doubles as the layering proof: to compile in its new home the
manager loses
channelId, theSdsChannelIDtype, the SDS import, andbrokerCtx— all channels-layer concerns. Rate limiting is a node-wideproperty of the sender's RLN identity, not a per-channel one, so nothing
above needs the channel identity back.
The event-emission API is replaced with a direct call:
The epoch fields (
epochPeriodSec,currentEpochStart,sentInCurrentEpoch,queue,dequeueReady,resetEpoch) are keptas-is: this PR changes the component's home and API surface, not the
epoch mechanism.
3. Meter SendService transmissions through the manager
MessagingClientConfgains arateLimit: RateLimitConfigfield(defaults:
DefaultEpochPeriodSec/DefaultMessagesPerEpoch, carriedas a field default so every construction site inherits it).
MessagingClient.newconstructs the manager and hands it toSendService, which consultsadmit()before the firsttransmission of a task — in
send()and in the retry loop, guarded byfirstPropagatedTime.isNone()so re-publishes of an already-propagatedmessage (identical bytes) skip admission. An over-budget task parks in
the task cache as
NextRoundRetry; the 1s service loop re-admits it asthe epoch rolls over.
Metering at the transmission stage rather than at
MessagingClient.sendis deliberate:
dispatchRepair, which documents "Pacing isdone by SDS itself") dispatch through the same
MessagingSendbrokeras user sends. An API-entry gate would let the messaging limiter
reject repair traffic — exactly when the reliability layer is
recovering from loss. At the transmission stage, SDS decides that a
repair is needed and the scheduler decides when it fits the budget.
DeliveryTaskeach), which matchesRLN accounting: every SDS segment is a separate relay message needing
its own proof.
loop;
SendServicealready is one.Behaviour
Unchanged.
admit()is a pass-through skeleton (return ok()), and theconfig default leaves
enabled: false. This PR is the relocation andthe seam; enforcement lands separately (see below).
Not touched
registration.
ReliableChannelManagerConfstill carriesrateLimitEnabled/rateLimitEpochPeriodSec/rateLimitMessagesPerEpoch. Post-movenothing reads them, but
tests/api/test_conf.nimexercises them viachannelsOverridesJSON, so removing them is a follow-up API decision.Tests
tests/messaging/test_rate_limit_manager.nim(new) pins the currentcontract: disabled admission is a pass-through, and — explicitly
documented in the test — enabled admission is too, flipping red when
real enforcement lands.
tests/channels/test_reliable_channel_send_receive.nimupdated forthe dropped constructor param; the e2e roundtrips are unchanged.
Follow-up
Per-epoch budgeting, RLN proof attach at the transmission stage, and
RLN-rejection handling in the retry loop are already staged on
feat/rate-limit-enforcement(stacked on this branch, targets #3855).Quota initialization/persistence is #3838.
🤖 Generated with Claude Code
Issue
closes #3953