Skip to content

Commit

Permalink
Merge pull request #127 from upstash/hotfix-bump-redis
Browse files Browse the repository at this point in the history
Bump Upstash Redis
  • Loading branch information
CahidArda authored Oct 23, 2024
2 parents 235762b + 0dfb86b commit c667b63
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 32 deletions.
8 changes: 2 additions & 6 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ jobs:
run: bun run test

cloudflare-workers-local:
needs:
- test
runs-on: ubuntu-latest
steps:
- name: Setup repo
Expand Down Expand Up @@ -127,8 +125,6 @@ jobs:
DEPLOYMENT_URL: https://upstash-ratelimit.upsdev.workers.dev

nextjs-local:
needs:
- test
runs-on: ubuntu-latest
steps:
- name: Setup repo
Expand Down Expand Up @@ -195,8 +191,8 @@ jobs:
VERCEL_PROJECT_ID: "prj_NSOSq2ZawugKhtZGb3ViHX4b56hx"
working-directory: examples/nextjs

- name: Install dependencies
run: bun install
- name: Install @upstash/ratelimit canary version
run: npm install @upstash/ratelimit@${{needs.release.outputs.version}}
working-directory: examples/nextjs

- name: Build Project
Expand Down
Binary file modified bun.lockb
Binary file not shown.
4 changes: 2 additions & 2 deletions examples/cloudflare-workers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"deploy": "wrangler publish"
},
"dependencies": {
"@upstash/ratelimit": "^1.0.3",
"@upstash/redis": "^1.20.6"
"@upstash/ratelimit": "latest",
"@upstash/redis": "latest"
}
}
1 change: 0 additions & 1 deletion examples/nextjs/app/api/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const redis = new Redis({

// Create a new ratelimiter
const ratelimit = new Ratelimit({
// @ts-ignore
redis,
limiter: Ratelimit.slidingWindow(10, "10 s"),
prefix: "@upstash/ratelimit",
Expand Down
6 changes: 3 additions & 3 deletions examples/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"lint": "next lint"
},
"dependencies": {
"@upstash/ratelimit": "^1.1.3",
"@upstash/redis": "^1.34.2",
"@upstash/ratelimit": "latest",
"@upstash/redis": "latest",
"@vercel/functions": "^1.0.2",
"next": "14.2.3",
"react": "^18",
Expand All @@ -30,4 +30,4 @@
},
"module": "index.ts",
"type": "module"
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.4.0",
"@upstash/redis": "^1.31.5",
"@upstash/redis": "^1.34.3",
"bun-types": "latest",
"eslint": "^9.10.0",
"eslint-plugin-unicorn": "^55.0.0",
Expand Down
3 changes: 2 additions & 1 deletion src/cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Ratelimit } from "./index";
test("ephemeral cache", async () => {
const maxTokens = 10;
const redis = Redis.fromEnv();
await redis.scriptFlush()

const metrics: Record<string | symbol, number> = {};

Expand Down Expand Up @@ -37,7 +38,7 @@ test("ephemeral cache", async () => {
}

expect(passes).toBeLessThanOrEqual(10);
expect(metrics.evalsha).toBe(11);
expect(metrics.evalsha).toBe(12);
expect(reasons).toContain("cacheBlock")

await new Promise((r) => setTimeout(r, 5000));
Expand Down
34 changes: 33 additions & 1 deletion src/deny-list/ip-deny-list.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { beforeEach, describe, expect, test } from "bun:test";
import { checkDenyList } from "./deny-list";
import { disableIpDenyList, updateIpDenyList } from "./ip-deny-list";
import { DenyListExtension, IpDenyListKey, IpDenyListStatusKey } from "../types";
import { Ratelimit } from "..";

describe("should update ip deny list status", async () => {
const redis = Redis.fromEnv();
Expand Down Expand Up @@ -139,6 +140,37 @@ describe("should update ip deny list status", async () => {
expect(newStatus).toBe("valid")
expect(newStatusTTL).toBeGreaterThan(1000)
})

test("should be able to use ratelimit with deny list", async () => {

/**
* When enableProtection is set to true, there was an error in the
* @upstash/ratelimit 2.0.3 release. Because the @upstash/redis
* uses auto-pipelining by default, the client would send the
* EVALSHA and the protection EVAL at the same time.
*
* When the db loses its scripts after a SCRIPT FLUSH or when
* ratelimit is used in a new DB, the EVALSHA will fail. But
* because since the EVAL and EVALSHA are pipelined, they will
* both fail and EVAL will get the EVALSHA's error.
*/
const redis = Redis.fromEnv({ enableAutoPipelining: true });

// flush the db to make sure
await redis.scriptFlush()
// sleep for two secs
await new Promise(r => setTimeout(r, 2000));

const ratelimit = new Ratelimit({
limiter: Ratelimit.fixedWindow(2, "1s"),
redis,
enableProtection: true
})

const { success, remaining } = await ratelimit.limit("ip-deny-list")
expect(success).toBeTrue()
expect(remaining).toBe(1)
})
})

describe("should only allow threshold values from 1 to 8", async () => {
Expand Down Expand Up @@ -177,4 +209,4 @@ describe("should only allow threshold values from 1 to 8", async () => {
expect(error.name).toEqual("ThresholdError")
}
})
})
})
3 changes: 2 additions & 1 deletion src/deny-list/ip-deny-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ export const updateIpDenyList = async (

// delete the old ip deny list and create new one
transaction.del(ipDenyList)
transaction.sadd(ipDenyList, ...allIps)

transaction.sadd(ipDenyList, allIps.at(0), ...allIps.slice(1))

// make all deny list and ip deny list disjoint by removing duplicate
// ones from ip deny list
Expand Down
24 changes: 24 additions & 0 deletions src/hash.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Redis } from "@upstash/redis";
import { describe, test } from "bun:test";
import { safeEval } from "./hash";
import { SCRIPTS } from "./lua-scripts/hash";

const redis = Redis.fromEnv();

describe("should set hash correctly", () => {
test("should set hash in new db correctly", async () => {
await redis.scriptFlush()

// sleep for two secs
await new Promise(r => setTimeout(r, 2000));

await safeEval(
{
redis
},
SCRIPTS.singleRegion.fixedWindow.limit,
["id"],
[10, 1]
)
})
})
24 changes: 8 additions & 16 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Pipeline } from "@upstash/redis";
import type { Redis as RedisCore } from "@upstash/redis";
import type { Geo } from "./analytics";

/**
Expand Down Expand Up @@ -123,25 +123,17 @@ export type LimitOptions = {
* This is all we need from the redis sdk.
*/
export type Redis = {
sadd: <TData>(key: string, ...members: TData[]) => Promise<number>;
sadd: RedisCore["sadd"]

hset: <TValue>(key: string, obj: { [key: string]: TValue }) => Promise<number>;
hset: RedisCore["hset"]

eval: <TArgs extends unknown[], TData = unknown>(
...args: [script: string, keys: string[], args: TArgs]
) => Promise<TData>;
eval: RedisCore["eval"]

evalsha: <TArgs extends unknown[], TData = unknown>(
...args: [sha1: string, keys: string[], args: TArgs]
) => Promise<TData>;
evalsha: RedisCore["evalsha"]

scriptLoad: (
...args: [script: string]
) => Promise<string>;
scriptLoad: RedisCore["scriptLoad"]

smismember: (
key: string, members: string[]
) => Promise<IsDenied[]>;
smismember: RedisCore["smismember"]

multi: () => Pipeline
multi: RedisCore["multi"]
}

0 comments on commit c667b63

Please sign in to comment.