Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,24 @@ export const queryRatelimitOverviewLogs = t.procedure
.input(ratelimitQueryOverviewLogsPayload)
.output(RatelimitOverviewLogsResponse)
.query(async ({ ctx, input }) => {
const ratelimitNamespaces = await db.query.ratelimitNamespaces
.findMany({
const ratelimitNamespace = await db.query.ratelimitNamespaces
.findFirst({
where: (table, { and, eq, isNull }) =>
and(
eq(table.workspaceId, ctx.workspace.id),
and(eq(table.id, input.namespaceId), isNull(table.deletedAtM)),
eq(table.id, input.namespaceId),
isNull(table.deletedAtM),
),
})
.catch((_err) => {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message:
"Failed to retrieve ratelimit timeseries analytics due to a workspace error. If this issue persists, please contact support@unkey.dev with the time this occurred.",
"Failed to retrieve ratelimit namespace. If this issue persists, please contact support@unkey.dev",
});
});

if (!ratelimitNamespaces) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Ratelimit namespaces not found, please contact support using support@unkey.dev.",
});
}

if (ratelimitNamespaces.length === 0) {
if (!ratelimitNamespace) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Namespace not found",
Expand All @@ -58,7 +52,7 @@ export const queryRatelimitOverviewLogs = t.procedure
...transformedInputs,
cursorTime: input.cursor ?? null,
workspaceId: ctx.workspace.id,
namespaceId: ratelimitNamespaces[0].id,
namespaceId: ratelimitNamespace.id,
});

const [countResult, logsResult] = await Promise.all([countQuery, logsQuery]);
Expand All @@ -70,7 +64,11 @@ export const queryRatelimitOverviewLogs = t.procedure
});
}

const logsWithOverrides = await checkIfIdentifierHasOverride(logsResult.val);
const logsWithOverrides = await checkIfIdentifierHasOverride(
logsResult.val,
ratelimitNamespace.id,
ctx.workspace.id,
);

const response: RatelimitOverviewLogsResponse = {
ratelimitOverviewLogs: logsWithOverrides,
Expand All @@ -85,10 +83,13 @@ export const queryRatelimitOverviewLogs = t.procedure
return response;
});

async function checkIfIdentifierHasOverride(logs: RatelimitOverviewLog[]) {
async function checkIfIdentifierHasOverride(
logs: RatelimitOverviewLog[],
namespaceId: string,
workspaceId: string,
) {
const identifiers = [...new Set(logs.map((log) => log.identifier))];

// if there are no identifiers to check
if (identifiers.length === 0) {
return logs.map((log) => ({
...log,
Expand All @@ -98,8 +99,13 @@ async function checkIfIdentifierHasOverride(logs: RatelimitOverviewLog[]) {

const overrides = await db.query.ratelimitOverrides
.findMany({
where: (table, { and, isNull, inArray }) =>
and(inArray(table.identifier, identifiers), isNull(table.deletedAtM)),
where: (table, { and, isNull, inArray, eq }) =>
and(
eq(table.namespaceId, namespaceId),
eq(table.workspaceId, workspaceId),
inArray(table.identifier, identifiers),
isNull(table.deletedAtM),
),
columns: {
identifier: true,
limit: true,
Expand Down
72 changes: 38 additions & 34 deletions go/benchmarks/keyverify.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import http from 'k6/http';
import { check } from 'k6';
import { Rate, Trend } from 'k6/metrics';

import { check } from "k6";
import http from "k6/http";
import { Trend } from "k6/metrics";

// Custom metrics
const requestLatencyTrend = new Trend('request_latency', true);
const requestLatencyTrend = new Trend("request_latency", true);

const loadZones = [
'amazon:us:ashburn', // US East
"amazon:us:ashburn", // US East
// 'amazon:us:portland', // US West
// 'amazon:ie:dublin', // Europe West
// 'amazon:de:frankfurt', // Europe Central
Expand All @@ -24,62 +23,67 @@ const distribution = {};
loadZones.forEach((zone, index) => {
distribution[zone] = {
loadZone: zone,
percent: index === loadZones.length - 1 ? 100 - (equalPercent * (loadZones.length - 1)) : equalPercent
percent:
index === loadZones.length - 1 ? 100 - equalPercent * (loadZones.length - 1) : equalPercent,
};
});

export const options = {
cloud: {
project: "3788521",
distribution: distribution
distribution: distribution,
},
stages: [
{ duration: '10m', target: 10 }, // 10 req/s for 1 minute
{ duration: "10m", target: 10 }, // 10 req/s for 1 minute
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95% of requests must complete below 500ms
checks: ['rate>0.99'], // 99% of checks must pass
http_req_duration: ["p(95)<500"], // 95% of requests must complete below 500ms
checks: ["rate>0.99"], // 99% of checks must pass
},
};

const UNKEY_ROOT_KEY = __ENV.UNKEY_ROOT_KEY;
const KEY = __ENV.KEY;

if (!UNKEY_ROOT_KEY) {
throw new Error('UNKEY_ROOT_KEY environment variable is required');
throw new Error("UNKEY_ROOT_KEY environment variable is required");
}

if (!KEY) {
throw new Error('KEY environment variable is required');
throw new Error("KEY environment variable is required");
}

const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${UNKEY_ROOT_KEY}`,
"Content-Type": "application/json",
Authorization: `Bearer ${UNKEY_ROOT_KEY}`,
};



export default function () {



const response = Math.random() < 0.5
? http.post('https://api.unkey.dev/v1/keys.verifyKey', JSON.stringify({
key: KEY,
}), {
headers: headers,
tags: { version: 'v1' },
})
: http.post('https://api.unkey.com/v2/keys.verifyKey', JSON.stringify({
key: KEY
}), {
headers: headers,
tags: { version: 'v2' },
});
const response =
Math.random() < 0.5
? http.post(
"https://api.unkey.dev/v1/keys.verifyKey",
JSON.stringify({
key: KEY,
}),
{
headers: headers,
tags: { version: "v1" },
},
)
: http.post(
"https://api.unkey.com/v2/keys.verifyKey",
JSON.stringify({
key: KEY,
}),
{
headers: headers,
tags: { version: "v2" },
},
);

check(response, {
'status is 200': (r) => r.status === 200,
"status is 200": (r) => r.status === 200,
});

requestLatencyTrend.add(response.timings.duration, { url: response.request.url });
Expand Down
87 changes: 45 additions & 42 deletions go/benchmarks/ratelimit.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import http from 'k6/http';
import { check } from 'k6';
import { Rate, Trend } from 'k6/metrics';

import { check } from "k6";
import http from "k6/http";
import { Trend } from "k6/metrics";

// Custom metrics
const requestLatencyTrend = new Trend('request_latency', true);
const requestLatencyTrend = new Trend("request_latency", true);

const loadZones = [
'amazon:us:ashburn', // US East
"amazon:us:ashburn", // US East
// 'amazon:us:portland', // US West
// 'amazon:ie:dublin', // Europe West
// 'amazon:de:frankfurt', // Europe Central
Expand All @@ -24,70 +23,74 @@ const distribution = {};
loadZones.forEach((zone, index) => {
distribution[zone] = {
loadZone: zone,
percent: index === loadZones.length - 1 ? 100 - (equalPercent * (loadZones.length - 1)) : equalPercent
percent:
index === loadZones.length - 1 ? 100 - equalPercent * (loadZones.length - 1) : equalPercent,
};
});

export const options = {
cloud: {
project: "3788521",
distribution: distribution
distribution: distribution,
},
stages: [
{ duration: '10m', target: 10 }, // 10 req/s for 1 minute
{ duration: "10m", target: 10 }, // 10 req/s for 1 minute
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95% of requests must complete below 500ms
checks: ['rate>0.99'], // 99% of checks must pass
http_req_duration: ["p(95)<500"], // 95% of requests must complete below 500ms
checks: ["rate>0.99"], // 99% of checks must pass
},
};

const UNKEY_ROOT_KEY = __ENV.UNKEY_ROOT_KEY;
const REGION = __ENV.REGION || 'local';
const REGION = __ENV.REGION || "local";

if (!UNKEY_ROOT_KEY) {
throw new Error('UNKEY_ROOT_KEY environment variable is required');
throw new Error("UNKEY_ROOT_KEY environment variable is required");
}

const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${UNKEY_ROOT_KEY}`,
"Content-Type": "application/json",
Authorization: `Bearer ${UNKEY_ROOT_KEY}`,
};



const identifiers = ['user1', 'user2', 'user3', 'user4', 'user5']
const identifiers = ["user1", "user2", "user3", "user4", "user5"];
export default function () {
// Randomly choose between v1 and v2 (50/50 split)

const identifier = identifiers[Math.floor(Math.random() * identifiers.length)];





const response = Math.random() < 0.5
? http.post('https://api.unkey.dev/v1/ratelimits.limit', JSON.stringify({
namespace: 'benchmark',
identifier,
limit: 100,
duration: 60000
}), {
headers: headers,
tags: { version: 'v1', region: REGION },
})
: http.post('https://api.unkey.com/v2/ratelimit.limit', JSON.stringify({
namespace: 'benchmark',
identifier,
limit: 100,
duration: 60000
}), {
headers: headers,
tags: { version: 'v2', region: REGION },
});
const response =
Math.random() < 0.5
? http.post(
"https://api.unkey.dev/v1/ratelimits.limit",
JSON.stringify({
namespace: "benchmark",
identifier,
limit: 100,
duration: 60000,
}),
{
headers: headers,
tags: { version: "v1", region: REGION },
},
)
: http.post(
"https://api.unkey.com/v2/ratelimit.limit",
JSON.stringify({
namespace: "benchmark",
identifier,
limit: 100,
duration: 60000,
}),
{
headers: headers,
tags: { version: "v2", region: REGION },
},
);

check(response, {
'status is 200': (r) => r.status === 200,
"status is 200": (r) => r.status === 200,
});

requestLatencyTrend.add(response.timings.duration, { url: response.request.url, region: REGION });
Expand Down
Loading