Skip to content

Commit

Permalink
eng 135 wrap all db reads with a retry (#1708)
Browse files Browse the repository at this point in the history
* refactor(init.ts): increase database connection retry to 3

* fix(ratelimit): update error handling in DurableObjectRatelimiter
  • Loading branch information
chronark authored May 31, 2024
1 parent fb81d90 commit d6059b3
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 15 deletions.
19 changes: 19 additions & 0 deletions __checks__/api.check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ApiCheck, AssertionBuilder } from "checkly/constructs";

new ApiCheck("books-api-check-1", {
name: "Books API",
alertChannels: [],
degradedResponseTime: 10000,
maxResponseTime: 20000,
request: {
url: "https://danube-web.shop/api/books",
method: "GET",
followRedirects: true,
skipSSL: false,
assertions: [
AssertionBuilder.statusCode().equals(200),
AssertionBuilder.jsonBody("$[0].id").isNotNull(),
],
},
runParallel: true,
});
15 changes: 15 additions & 0 deletions __checks__/heartbeat.check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { HeartbeatCheck } from "checkly/constructs";

// Heartbeat checks allow you to monitor jobs or recurring tasks.
// This feature is only available on paid plans.
// Upgrade your plan to start using it https://app.checklyhq.com/new-billing
// If you're already on a paid plan, uncomment the following lines to create a heartbeat check.

/* new HeartbeatCheck('heartbeat-check-1', {
name: 'Send weekly newsletter job',
period: 1,
periodUnit: 'hours',
grace: 30,
graceUnit: 'minutes',
})
*/
11 changes: 11 additions & 0 deletions __checks__/homepage.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { expect, test } from "@playwright/test";

// You can override the default Playwright test timeout of 30s
// test.setTimeout(60_000);

test("webshop homepage", async ({ page }) => {
const response = await page.goto("https://danube-web.shop");
expect(response?.status()).toBeLessThan(400);
await expect(page).toHaveTitle(/Danube WebShop/);
await page.screenshot({ path: "homepage.jpg" });
});
19 changes: 19 additions & 0 deletions apps/api/__checks__/v1_liveness.check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ApiCheck, AssertionBuilder } from "checkly/constructs";

new ApiCheck("/v1/liveness", {
name: "Liveness",
alertChannels: [],
degradedResponseTime: 10000,
maxResponseTime: 20000,
request: {
url: "https://api.unkey.dev/v1/liveness",
method: "GET",
followRedirects: true,
skipSSL: false,
assertions: [
AssertionBuilder.statusCode().equals(200),
AssertionBuilder.jsonBody("$[0].id").isNotNull(),
],
},
runParallel: true,
});
42 changes: 27 additions & 15 deletions apps/api/src/pkg/ratelimit/durable_object.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { zValidator } from "@hono/zod-validator";
import { Hono } from "hono";
import { z } from "zod";
import { ConsoleLogger } from "../logging";

type Memory = {
current: number;
Expand Down Expand Up @@ -35,25 +36,36 @@ export class DurableObjectRatelimiter {
}),
),
async (c) => {
const { reset, cost, limit } = c.req.valid("json");
if (!this.memory.alarmScheduled) {
this.memory.alarmScheduled = reset;
await this.state.storage.setAlarm(this.memory.alarmScheduled);
}
if (this.memory.current + cost > limit) {
try {
const { reset, cost, limit } = c.req.valid("json");
if (!this.memory.alarmScheduled) {
this.memory.alarmScheduled = reset;
await this.state.storage.setAlarm(this.memory.alarmScheduled);
}
if (this.memory.current + cost > limit) {
return c.json({
success: false,
current: this.memory.current,
});
}
this.memory.current += cost;

await this.state.storage.put(this.storageKey, this.memory);

return c.json({
success: false,
success: true,
current: this.memory.current,
});
}
this.memory.current += cost;

await this.state.storage.put(this.storageKey, this.memory);
} catch (e) {
new ConsoleLogger({
requestId: "todo",
}).error("caught durable object error", {
message: (e as Error).message,
memory: this.memory,
});

return c.json({
success: true,
current: this.memory.current,
});
throw e;
}
},
);
}
Expand Down
45 changes: 45 additions & 0 deletions checkly.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { defineConfig } from "checkly";

/**
* See https://www.checklyhq.com/docs/cli/project-structure/
*/
const config = defineConfig({
/* A human friendly name for your project */
projectName: "unkey",
/** A logical ID that needs to be unique across your Checkly account,
* See https://www.checklyhq.com/docs/cli/constructs/ to learn more about logical IDs.
*/
logicalId: "unkey",
/* An optional URL to your Git repo */
repoUrl: "https://github.com/unkeyed/unkey",
/* Sets default values for Checks */
checks: {
/* A default for how often your Check should run in minutes */
frequency: 10,
/* Checkly data centers to run your Checks as monitors */
locations: ["us-east-1", "eu-west-1"],
/* An optional array of tags to organize your Checks */
tags: ["mac"],
/** The Checkly Runtime identifier, determining npm packages and the Node.js version available at runtime.
* See https://www.checklyhq.com/docs/cli/npm-packages/
*/
runtimeId: "2023.09",
/* A glob pattern that matches the Checks inside your repo, see https://www.checklyhq.com/docs/cli/using-check-test-match/ */
checkMatch: "**/__checks__/**/*.check.ts",
/* Global configuration option for Playwright-powered checks. See https://docs/browser-checks/playwright-test/#global-configuration */
browserChecks: {
/* A glob pattern matches any Playwright .spec.ts files and automagically creates a Browser Check. This way, you
* can just write native Playwright code. See https://www.checklyhq.com/docs/cli/using-check-test-match/
* */
testMatch: "**/__checks__/**/*.spec.ts",
},
},
cli: {
/* The default datacenter location to use when running npx checkly test */
runLocation: "eu-west-1",
/* An array of default reporters to use when a reporter is not specified with the "--reporter" flag */
reporters: ["list"],
},
});

export default config;

1 comment on commit d6059b3

@vercel
Copy link

@vercel vercel bot commented on d6059b3 May 31, 2024

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

planetfall – ./apps/planetfall

planetfall-unkey.vercel.app
planetfall-git-main-unkey.vercel.app
planetfall-two.vercel.app
planetfall.unkey.dev

Please sign in to comment.