Skip to content

Add pacing logic to Lighter - #164

Merged
hacheigriega merged 4 commits into
mainfrom
hy/rate-limit-metrics
Aug 13, 2026
Merged

Add pacing logic to Lighter#164
hacheigriega merged 4 commits into
mainfrom
hy/rate-limit-metrics

Conversation

@hacheigriega

@hacheigriega hacheigriega commented Aug 11, 2026

Copy link
Copy Markdown
Member

Motivation

To prevent hitting Lighter's rate limits

Explanation of Changes

To address the limit of "Max Messages Sent By Client Per Minute" set at 200, we add a pacing logic to the Lighter module WS client by using a single outbound queue parametrized by maxMessagesPerMinute (defaults to 180).

Also adds parsing and logging of error frames sent by Lighter and Binance. (These are separate from transport-level WS failures that end up in the error handler)

Testing

A few unit tests.
Also tested locally that we no longer get "Too Many Websocket Messages" errors upon burst of requests that we get on main.

@hacheigriega
hacheigriega force-pushed the hy/rate-limit-metrics branch from 0b74534 to 30ceab5 Compare August 11, 2026 14:22
@hacheigriega
hacheigriega marked this pull request as ready for review August 11, 2026 16:34
@hacheigriega
hacheigriega force-pushed the hy/rate-limit-metrics branch from 144a4f7 to 9e17d40 Compare August 11, 2026 18:13
@hacheigriega
hacheigriega requested a review from a team August 11, 2026 18:15

@gluax gluax left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but maybe a second opinion from someone more familiar with TS/DP?

@Thomasvdam Thomasvdam left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can express the pacing queue more elegantly with a semaphore.

import { NodeRuntime } from "@effect/platform-node";
import { Duration, Effect, Schedule, Stream } from "effect";

const MAX_MESSAGES_PER_WINDOW = 5;
const WINDOW_SIZE_SECONDS = 5

const task = Effect.fn(function* (a: number) {
	yield* Effect.logInfo();
	yield* Effect.sleep(Duration.seconds(WINDOW_SIZE));
});

const program = Effect.gen(function* () {
	const mutex = yield* Effect.makeSemaphore(MAX_MESSAGES_PER_WINDOW);

	const stream = Stream.iterate(0, (n) => n + 1).pipe(
		Stream.schedule(
			Schedule.spaced(Duration.seconds(.5)).pipe(
				Schedule.jitteredWith({ min: 0.8, max: 1.2 }),
			),
		),
	);

	yield* stream.pipe(
		Stream.mapEffect(
			(n) =>
				mutex
					.withPermits(1)(
						Effect.gen(function* () {
							yield* task(n);
						}),
					),
			{ concurrency: "unbounded" },
		),
		Stream.runDrain,
	);
}).pipe(
	Effect.withSpan("program", {
		attributes: { source: "Playground" },
	}),
);

program.pipe(NodeRuntime.runMain);

This produces the following output:

[11:32:14.533] INFO (#6):
[11:32:15.134] INFO (#9):
[11:32:15.636] INFO (#12):
[11:32:16.078] INFO (#15):
[11:32:16.623] INFO (#18):
[11:32:19.541] INFO (#21):
[11:32:20.137] INFO (#24):
[11:32:20.639] INFO (#27):
[11:32:21.082] INFO (#30):
[11:32:21.626] INFO (#33):
[11:32:24.545] INFO (#36):
[11:32:25.144] INFO (#39):
[11:32:25.643] INFO (#42):
[11:32:26.087] INFO (#45):
[11:32:26.631] INFO (#48):
[11:32:29.550] INFO (#51):
[11:32:30.148] INFO (#54):

Which seems like the behaviour we're looking for? I think this pattern also makes it easier to abstract into a utility and test separately.

Comment thread workspace/data-proxy/src/modules/lighter/ws-client.ts Outdated
Comment thread workspace/data-proxy/src/modules/lighter/ws-client.test.ts Outdated
@hacheigriega
hacheigriega force-pushed the hy/rate-limit-metrics branch from 63cfd53 to c7a7f77 Compare August 13, 2026 18:30
Add pacing logic using an outbound queue parametrized by
maxMessagesPerSecond.
@hacheigriega
hacheigriega force-pushed the hy/rate-limit-metrics branch from c7a7f77 to ad46bb0 Compare August 13, 2026 18:33
@hacheigriega
hacheigriega merged commit ad46bb0 into main Aug 13, 2026
2 checks passed
@hacheigriega
hacheigriega deleted the hy/rate-limit-metrics branch August 13, 2026 20:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants