-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ioredis compatibility #115
Comments
Totally doable, but our main focus on serverless environments. Maybe we can let people use Edit: |
@ogzhanolguncu If the team is moving forward with this integration, I would like to work on it. |
@ogzhanolguncu the linked solution does not work, up stash rate limit depends on more functions by now. ![]() using ioredis for these methods seems to not work either out of the box, think the adapter needs more effort to be made working. would love this to be part of ratelimit-js, then at least its clear when compatibility breaks. |
Any chance this is going to land sometime? |
Sorry to say that, but team don't wanna move forward with that approach for now. But, we can't say you guys can't come up with an adapter 😉 If you know what I mean. So feel free to @sourabpramanik or @bkniffler make your own adapters. |
Gotcha @ogzhanolguncu |
If you have a working solution make sure to put it here so other people can use it. |
I got it working with this but it has a lot of type assertions which is not ideal: import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from 'ioredis'
const redis = new Redis(`redis://localhost:6379`)
const limiter = new Ratelimit({
redis: {
sadd: async <TData>(key: string, ...members: TData[]) =>
redis.sadd(key, ...members.map(String)),
eval: async <TArgs extends unknown[], TData = unknown>(
script: string,
keys: string[],
args: TArgs,
) => redis.eval(script, keys.length, ...keys, ...(args ?? []).map(String)) as Promise<TData>,
scriptLoad: async (script: string) => redis.script('LOAD', script) as Promise<string>,
smismember: async (key: string, members: unknown[]) =>
redis.smismember(key, ...(members as string[])) as Promise<(0 | 1)[]>,
evalsha: async <TData>(sha1: string, keys: string[], args: unknown[]) =>
redis.evalsha(sha1, keys.length, ...keys, ...(args as string[])) as TData,
hset: async <TData>(key: string, kv: Record<string, TData>) => redis.hset(key, kv),
} as any,
// ...
}) |
which version do you use? type Redis = Pick<Redis$1, "get" | "set">;
type RegionRatelimitConfig = {
/**
* Instance of `@upstash/redis`
* @see https://github.com/upstash/upstash-redis#quick-start
*/
redis: Redis;
...
} |
I tried it with just get and set but it actually uses the functions from the old type. The type is just wrong. |
For simple usage, the old type is sufficient. But we added opt-in features later which required other methods too. Features such as traffic protection. |
To make import { Ratelimit } from '@upstash/ratelimit';
import Redis from 'ioredis';
// Define the Redis interface expected by @upstash/ratelimit
interface RatelimitRedis {
get: (key: string) => Promise<string | null>;
set: (key: string, value: string, options?: { ex?: number }) => Promise<unknown>;
sadd: <TData>(key: string, ...members: TData[]) => Promise<number>;
eval: <TArgs extends unknown[], TData = unknown>(
script: string,
keys: string[],
args: TArgs
) => Promise<TData>;
scriptLoad: (script: string) => Promise<string>;
smismember: (key: string, members: unknown[]) => Promise<(0 | 1)[]>;
evalsha: <TData>(sha1: string, keys: string[], args: unknown[]) => Promise<TData>;
hset: <TData>(key: string, kv: Record<string, TData>) => Promise<number>;
}
// Create an ioredis instance
const ioredis = new Redis('redis://localhost:6379');
// Implement the custom Redis adapter
const customRedis: RatelimitRedis = {
get: async (key: string) => ioredis.get(key),
set: async (key: string, value: string, options?: { ex?: number }) => {
if (options?.ex) {
return ioredis.set(key, value, 'EX', options.ex);
}
return ioredis.set(key, value);
},
sadd: async <TData>(key: string, ...members: TData[]) =>
ioredis.sadd(key, ...members.map(String)),
eval: async <TArgs extends unknown[], TData = unknown>(
script: string,
keys: string[],
args: TArgs
) => ioredis.eval(script, keys.length, ...keys, ...(args ?? []).map(String)) as Promise<TData>,
scriptLoad: async (script: string) => ioredis.script('LOAD', script),
smismember: async (key: string, members: unknown[]) =>
ioredis.smismember(key, ...(members as string[])) as Promise<(0 | 1)[]>,
evalsha: async <TData>(sha1: string, keys: string[], args: unknown[]) =>
ioredis.evalsha(sha1, keys.length, ...keys, ...(args as string[])) as Promise<TData>,
hset: async <TData>(key: string, kv: Record<string, TData>) => ioredis.hset(key, kv),
};
// Initialize Ratelimit with the custom adapter
const limiter = new Ratelimit({
redis: customRedis,
limiter: Ratelimit.slidingWindow(10, '10 s'), // Example configuration
// Add other options as needed
});
// Example usage
async function testLimiter() {
const { success } = await limiter.limit('user_123');
console.log(success ? 'Request allowed' : 'Request blocked');
}
testLimiter(); |
On this topic, would it be feasible to make Currently, when integrating If the analytics integration is not tightly coupled with the core functionality of this package, it would be beneficial to allow us to opt out of it, particularly for use cases that do not require analytics and want to avoid unnecessary dependencies. |
Any chance we could get this ioredis compatible? Would like to use upstash via ioredis to remove http overhead, and ioredis is one of the recommended clients for upstash, but its not compatible with ratelimit-js.
The text was updated successfully, but these errors were encountered: