Skip to content

Commit

Permalink
uptime monitor sample (#37)
Browse files Browse the repository at this point in the history
* init

* Add gitignore, .dev.vars.example, and check in migration files

* Update wrangler in all package.json

* Update uptime-monitor package.json

* Remove typescript language server from example deps

* Update cloudflare workers types

* Code cleanup

* Remove honc-hatch comment

* Add a few notes and a format command to the uptime-monitor

* Update readme

---------

Co-authored-by: Micha 'mies' Hernandez van Leuffen <[email protected]>
Co-authored-by: Brett Beutell <[email protected]>
  • Loading branch information
3 people authored Dec 12, 2024
1 parent c7392d4 commit 23f4d46
Show file tree
Hide file tree
Showing 28 changed files with 1,094 additions and 127 deletions.
5 changes: 2 additions & 3 deletions examples/cf-retrieval-augmented-goose/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"db:migrate": "drizzle-kit migrate",
"db:setup": "npm run db:generate && npm run db:migrate",
"db:studio": "drizzle-kit studio",
"fiberplane": "pnpx @fiberplane/studio@canary",
"fiberplane": "npx @fiberplane/studio@latest",
"vectors:create": "tsx --tsconfig tsconfig.scripts.json scripts/create-vectors.ts",
"format": "biome check . --write"
},
Expand All @@ -34,7 +34,6 @@
"pgvector": "^0.2.0",
"tsx": "^4.19.2",
"typescript": "^5.5.4",
"typescript-language-server": "^4.3.3",
"wrangler": "3.92.0"
"wrangler": "^3.95.0"
}
}
2 changes: 1 addition & 1 deletion examples/goose-joke-generator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
"drizzle-kit": "^0.28.1",
"tsx": "^4.19.2",
"typescript": "^5.5.4",
"wrangler": "3.92.0"
"wrangler": "^3.95.0"
}
}
5 changes: 2 additions & 3 deletions examples/goose-review-bot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"db:seed": "tsx seed.ts",
"db:setup": "npm run db:generate && npm run db:migrate && npm run db:seed",
"db:studio": "drizzle-kit studio",
"fiberplane": "npx @fiberplane/studio@canary",
"fiberplane": "npx @fiberplane/studio@latest",
"format": "biome format . --write"
},
"dependencies": {
Expand All @@ -27,8 +27,7 @@
"drizzle-kit": "^0.28.1",
"tsx": "^4.19.2",
"typescript": "^5.5.4",
"typescript-language-server": "^4.3.3",
"wrangler": "3.92.0"
"wrangler": "^3.95.0"
},
"description": "an api that listens for github pull requests and does code reviews"
}
5 changes: 2 additions & 3 deletions examples/honcanator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"db:migrate": "drizzle-kit migrate",
"db:setup": "npm run db:generate && npm run db:migrate",
"db:studio": "drizzle-kit studio",
"fiberplane": "npx @fiberplane/studio@canary",
"fiberplane": "npx @fiberplane/studio@latest",
"format": "biome check . --write"
},
"dependencies": {
Expand All @@ -22,8 +22,7 @@
"drizzle-kit": "^0.28.1",
"tsx": "^4.19.2",
"typescript": "^5.5.4",
"typescript-language-server": "^4.3.3",
"wrangler": "3.92.0"
"wrangler": "^3.95.0"
},
"packageManager": "[email protected]+sha512.f549b8a52c9d2b8536762f99c0722205efc5af913e77835dbccc3b0b0b2ca9e7dc8022b78062c17291c48e88749c70ce88eb5a74f1fa8c4bf5e18bb46c8bd83a"
}
2 changes: 1 addition & 1 deletion examples/placegoose/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@
"@types/prismjs": "^1.26.5",
"drizzle-kit": "^0.28.1",
"tsx": "^4.19.2",
"wrangler": "3.92.0"
"wrangler": "^3.95.0"
}
}
2 changes: 2 additions & 0 deletions examples/uptime-monitor/.dev.vars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Connect to local fiberplane instance
FPX_ENDPOINT=http://localhost:8788/v1/traces
18 changes: 18 additions & 0 deletions examples/uptime-monitor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Normally you don't ignore this file, but it's nice to ignore it for the examples
.fpxconfig

# prod
dist/

# deps
node_modules/
.wrangler

# env
.env
.env.production
.dev.vars
.prod.vars

# misc
.DS_Store
122 changes: 122 additions & 0 deletions examples/uptime-monitor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
## 🪿 Website Uptime Monitor

A serverless website monitoring application built with the HONC stack (Hono, OpenTelemetry, and Cloudflare). This application allows you to monitor the uptime of websites by performing periodic health checks and storing the results in a D1 database.

### Features

- Monitor multiple websites simultaneously
- Configurable check intervals per website
- Track response times and HTTP status codes
- Calculate uptime percentages
- RESTful API for managing monitored websites
- Simple web interface to view monitored sites

### Technology Stack

- **Hono**: Lightweight web framework for Cloudflare Workers
- **D1**: Cloudflare's serverless SQL database
- **Drizzle ORM**: Type-safe database toolkit
- **Durable Objects**: For managing persistent monitoring schedules
- **OpenTelemetry**: For observability and monitoring

### Getting Started

[D1](https://developers.cloudflare.com/d1/) is Cloudflare's serverless SQL database. Running this application involves two key steps: first, setting up the project locally, and second, deploying it in production.

### Project Structure

```#
├── src
│ ├── index.tsx # Hono app entry point
│ └── db
│ └── schema.ts # Database schema
├── .dev.vars.example # Example .dev.vars file
├── .prod.vars.example # Example .prod.vars file
├── seed.ts # Optional script to seed the db
├── drizzle.config.ts # Drizzle configuration
├── package.json
├── tsconfig.json # TypeScript configuration
└── wrangler.toml # Cloudflare Workers configuration
```

### Commands for local development

Create a `.dev.vars` file from the example file:

```sh
cp .dev.vars.example .dev.vars
```

Run the migrations and (optionally) seed the database:

```sh
# this is a convenience script that runs db:touch, db:generate, db:migrate, and db:seed
npm run db:setup
```

Run the development server:

```sh
npm run dev
```

As you iterate on the database schema, you'll need to generate a new migration file and apply it like so:

```sh
npm run db:generate
npm run db:migrate
```

### Commands for deployment

Before deploying your worker to Cloudflare, ensure that you have a running D1 instance on Cloudflare to connect your worker to.

You can create a D1 instance by navigating to the `Workers & Pages` section and selecting `D1 SQL Database.`

Alternatively, you can create a D1 instance using the CLI:

```sh
npx wrangler d1 create <database-name>
```

After creating the database, update the `wrangler.toml` file with the database id.

```toml
[[d1_databases]]
binding = "DB"
database_name = "uptime-d1-database"
database_id = "<database-id-you-just-created>"
migrations_dir = "drizzle/migrations"
```

Include the following information in a `.prod.vars` file:

```sh
CLOUDFLARE_D1_TOKEN="" # An API token with D1 edit permissions. You can create API tokens from your Cloudflare profile
CLOUDFLARE_ACCOUNT_ID="" # Find your Account id on the Workers & Pages overview (upper right)
CLOUDFLARE_DATABASE_ID="" # Find the database ID under workers & pages under D1 SQL Database and by selecting the created database
```

If you haven’t generated the latest migration files yet, run:
```shell
npm run db:generate
```

Afterwards, run the migration script for production:
```shell
npm run db:migrate:prod
```

Change the name of the project in `wrangler.toml` if you want to, but for now it is:

```toml
name = "uptime-monitor"
```

Finally, deploy your worker

```shell
npm run deploy
```


4 changes: 4 additions & 0 deletions examples/uptime-monitor/biome.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"extends": ["../../biome.jsonc"]
}
68 changes: 68 additions & 0 deletions examples/uptime-monitor/drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import fs from "node:fs";
import path from "node:path";
import { config } from "dotenv";
import { defineConfig } from "drizzle-kit";

let dbConfig: ReturnType<typeof defineConfig>;
if (process.env.ENVIROMENT === "production") {
config({ path: "./.prod.vars" });
dbConfig = defineConfig({
schema: "./src/db/schema.ts",
out: "./drizzle/migrations",
dialect: "sqlite",
driver: "d1-http",
dbCredentials: {
accountId: process.env.CLOUDFLARE_ACCOUNT_ID ?? "",
databaseId: process.env.CLOUDFLARE_DATABASE_ID ?? "",
token: process.env.CLOUDFLARE_D1_TOKEN ?? "",
},
});
} else {
config({ path: "./.dev.vars" });
const localD1DB = getLocalD1DB();
if (!localD1DB) {
process.exit(1);
}

dbConfig = defineConfig({
schema: "./src/db/schema.ts",
out: "./drizzle/migrations",
dialect: "sqlite",
dbCredentials: {
url: localD1DB,
},
});
}

export default dbConfig;

function getLocalD1DB() {
try {
const basePath = path.resolve(".wrangler");
const files = fs
.readdirSync(basePath, { encoding: "utf-8", recursive: true })
.filter((f) => f.endsWith(".sqlite"));

// In case there are multiple .sqlite files, we want the most recent one.
files.sort((a, b) => {
const statA = fs.statSync(path.join(basePath, a));
const statB = fs.statSync(path.join(basePath, b));
return statB.mtime.getTime() - statA.mtime.getTime();
});
const dbFile = files[0];

if (!dbFile) {
throw new Error(`.sqlite file not found in ${basePath}`);
}

const url = path.resolve(basePath, dbFile);

return url;
} catch (err) {
if (err instanceof Error) {
console.log(`Error resolving local D1 DB: ${err.message}`);
} else {
console.log(`Error resolving local D1 DB: ${err}`);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CREATE TABLE `uptime_checks` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`websiteId` integer NOT NULL,
`timestamp` text NOT NULL,
`status` integer,
`responseTime` integer,
`isUp` integer NOT NULL,
FOREIGN KEY (`websiteId`) REFERENCES `websites`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE `websites` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`url` text NOT NULL,
`name` text NOT NULL,
`checkInterval` integer NOT NULL,
`createdAt` text NOT NULL
);
Loading

0 comments on commit 23f4d46

Please sign in to comment.