news 2026/9/15 19:48:26

使用 Encore.ts 构建事件驱动的 Uptime Monitor:从 0 到云端的完整实战教程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 Encore.ts 构建事件驱动的 Uptime Monitor:从 0 到云端的完整实战教程

使用 Encore.ts 构建事件驱动的 Uptime Monitor:从 0 到云端的完整实战教程

【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encore

本教程将基于开源仓库 encore 提供的 Encore.ts 开发框架,从零构建一个事件驱动架构的网站可用性监控系统(Uptime Monitor)。你将掌握 Encore.ts 的服务定义、API 端点、SQL 数据库迁移、Cron 定时任务、Pub/Sub 消息解耦、Secrets 密钥管理以及一键云端部署的完整实战能力,全部代码仅约 300 行。

1. 我们要构建什么

当你的网站宕机时,你希望第一时间收到通知,而不是等用户来抱怨。这就是 Uptime Monitor 存在的意义。

本教程将使用 Encore.ts 构建一个完整的上线监控系统,最终形态包含三个后端服务(sitemonitorslack)、两个 SQL 数据库、一个每小时触发的 Cron 任务、一个 Pub/Sub 主题及其订阅者,以及通过 Slack Webhook 发送告警的能力。

整个系统采用事件驱动架构:monitor服务周期性检查所有被监控站点,当某个站点从"在线"变为"离线"(或反之)时,向 Pub/Sub 主题发布一条消息;slack服务订阅该主题,自动把状态变更推送到 Slack 频道。架构图(由 Encore 自动生成的 Flow 图)中,白色盒子是服务,黑色盒子是 Pub/Sub 主题,可以参考 encore-flow 说明 了解这一可视化能力。

2. 创建 Encore 应用

🥐 首先创建一个新的 Encore 应用。教程提供了包含现成前端页面的起始分支,直接克隆即可:

$ encore app create uptime --example=github.com/encoredev/example-app-uptime/tree/starting-point-ts

如果你是第一次使用 Encore,会提示创建一个免费账号。这在后续需要 Encore 托管 secrets 或执行云端部署时是必需的。

💡 提示:本教程使用 🥐 标记每一个需要你亲手完成的操作步骤,跟着走即可。

创建完成后,应用目录内会有一个encore.app文件(这个文件持有应用的唯一 ID,用于将应用与 Encore 平台关联,后续部署时不要替换它)。

3. 创建 monitor 服务:编写第一个 API 端点

Encore.ts 中,服务是一个目录及其所有子目录的集合,通过一个名为encore.service.ts的文件来声明。

🥐 创建monitor目录和它的服务定义文件:

$ mkdir monitor $ touch monitor/encore.service.ts
-- monitor/encore.service.ts -- import { Service } from "encore.dev/service"; export default new Service("monitor");

从源码看,Service 类 的注释明确说明:它必须在名为encore.service.ts的文件中调用,以便 Encore 高效识别服务定义;服务的范围就是其所在目录及其全部子目录。构造函数还接受可选的cfg参数(目前支持配置middlewares中间件)。

3.1 编写 ping 端点

🥐 在monitor目录下创建ping.ts,定义pingAPI 端点:接收一个 URL,返回该站点当前是否在线:

-- monitor/ping.ts -- // Service monitor checks if a website is up or down. import { api } from "encore.dev/api"; export interface PingParams { url: string; } export interface PingResponse { up: boolean; } // Ping pings a specific site and determines whether it's up or down right now. export const ping = api<PingParams, PingResponse>( { expose: true, path: "/ping/:url", method: "GET" }, async ({ url }) => { // If the url does not start with "http:" or "https:", default to "https:". if (!url.startsWith("http:") && !url.startsWith("https:")) { url = "https://" + url; } try { // Make an HTTP request to check if it's up. const resp = await fetch(url, { method: "GET" }); // 2xx and 3xx status codes are considered up const up = resp.status >= 200 && resp.status < 300; return { up }; } catch (err) { return { up: false }; } } );

这里用到了api()这个 Encore.ts 的核心 API。查看 api/mod.ts 中的 APIOptions 定义,可以深入理解本例中几个选项的含义与更多可选配置:

  • path:路由路径。使用:定义单段路径参数(如/ping/:url),使用*匹配任意多段。如果不指定path,默认值是/<服务名>.<端点名>(例如本端点未指定时会是/monitor.ping)。
  • method:HTTP 方法,可以是单个方法、方法数组,或"*"匹配所有方法。本教程后续的site服务会展示 POST/GET/DELETE 的用法。
  • expose:是否将端点暴露为公网可访问。默认为false,此时端点只在 Encore 内部网络可达(这非常适合服务间调用,如后面monitor服务调用site服务)。
  • auth:是否要求请求携带有效认证信息,默认为false
  • bodyLimit:请求体大小上限(字节),默认 2MiB,设为null则不限。
  • tagssensitive:分别用于客户端生成过滤和从 trace 中剔除敏感请求信息。

3.2 在本地运行并测试

🥐 运行encore run启动应用,然后打开本地开发仪表盘 http://localhost:9400,在 API Explorer 中调用monitor.ping,传入google.com。你也可以直接查看请求的响应、日志和调用链(trace)。

如果更喜欢命令行,在另一个终端执行:

$ curl http://localhost:4000/ping/google.com

返回结果:

{"up": true}

再试试负面用例httpstat.us/400some-non-existing-url.com,应返回{"up": false}——测试负面用例永远是值得养成的习惯。

3.3 为 ping 端点编写自动化测试

🥐 创建monitor/ping.test.ts,防止端点日后被改坏:

-- monitor/ping.test.ts -- import { describe, expect, test } from "vitest"; import { ping } from "./ping"; describe("ping", () => { test.each([ // Test both with and without "https://" { site: "google.com", expected: true }, { site: "https://encore.dev", expected: true }, // 4xx and 5xx should considered down. { site: "https://not-a-real-site.xyz", expected: false }, // Invalid URLs should be considered down. { site: "invalid://scheme", expected: false }, ])( `should verify that $site is ${"$expected" ? "up" : "down"}`, async ({ site, expected }) => { const resp = await ping({ url: site }); expect(resp.up).toBe(expected); }, ); });

🥐 运行encore test

$ encore test DEV v1.3.0 ✓ monitor/ping.test.ts (4) ✓ ping (4) ✓ should verify that 'google.com' is up ✓ should verify that 'https://encore.dev' is up ✓ should verify that 'https://not-a-real-site.xyz' is down ✓ should verify that 'invalid://scheme' is down Test Files 1 passed (1) Tests 4 passed (4) Start at 12:31:03 Duration 460ms (transform 43ms, setup 0ms, collect 59ms, tests 272ms, environment 0ms, prepare 47ms) PASS Waiting for file changes...

4. 创建 site 服务:用 Knex.js 管理被监控站点

下一步需要维护"要监控哪些网站"的列表。由于大部分接口是简单的 CRUD(增删改查),教程选用 Knex.js 这个 ORM 库来简化开发。

4.1 定义服务与数据库迁移

🥐 创建site服务:

$ mkdir site # Create a new directory in the application root $ touch site/encore.service.ts
-- site/encore.service.ts -- import { Service } from "encore.dev/service"; export default new Service("site");

🥐 为site服务添加 SQL 数据库。创建site/migrations目录,并在其中放置一个迁移文件1_create_tables.up.sql文件名有讲究,必须形如1_<名字>.up.sql

-- site/migrations/1_create_tables.up.sql -- CREATE TABLE site ( id SERIAL PRIMARY KEY, url TEXT NOT NULL UNIQUE );

🥐 安装依赖:

$ npm i knex pg

4.2 编写 CRUD 端点

🥐 创建site/site.ts

-- site/site.ts -- import { api } from "encore.dev/api"; import { SQLDatabase } from "encore.dev/storage/sqldb"; import knex from "knex"; // Site describes a monitored site. export interface Site { id: number; // ID is a unique ID for the site. url: string; // URL is the site's URL. } // AddParams are the parameters for adding a site to be monitored. export interface AddParams { // URL is the URL of the site. If it doesn't contain a scheme // (like "http:" or "https:") it defaults to "https:". url: string; } // Add a new site to the list of monitored websites. export const add = api( { expose: true, method: "POST", path: "/site" }, async (params: AddParams): Promise<Site> => { const site = (await Sites().insert({ url: params.url }, "*"))[0]; return site; }, ); // Get a site by id. export const get = api( { expose: true, method: "GET", path: "/site/:id", auth: false }, async ({ id }: { id: number }): Promise<Site> => { const site = await Sites().where("id", id).first(); return site ?? Promise.reject(new Error("site not found")); }, ); // Delete a site by id. export const del = api( { expose: true, method: "DELETE", path: "/site/:id" }, async ({ id }: { id: number }): Promise<void> => { await Sites().where("id", id).delete(); }, ); export interface ListResponse { sites: Site[]; // Sites is the list of monitored sites } // Lists the monitored websites. export const list = api( { expose: true, method: "GET", path: "/site" }, async (): Promise<ListResponse> => { const sites = await Sites().select(); return { sites }; }, ); // Define a database named 'site', using the database migrations // in the "./migrations" folder. Encore automatically provisions, // migrates, and connects to the database. const SiteDB = new SQLDatabase("site", { migrations: "./migrations", }); const orm = knex({ client: "pg", connection: SiteDB.connectionString, }); const Sites = () => orm<Site>("site");

注意其中最关键的一行:new SQLDatabase("site", { migrations: "./migrations" })。这是 Encore.ts 的数据库声明方式——Encore 会自动完成数据库的供给(provision)、迁移(migrate)和连接(connect),你无需关心连接串管理。SiteDB.connectionString提供了运行时连接信息,可以无缝接入任意 ORM(这里是 Knex)。

4.3 验证数据库与端点

🥐 确保本机已安装并运行 Docker,然后重启encore run,Encore 会自动创建site数据库。可以在本地开发仪表盘(localhost:9400)的 Flow 架构图中确认数据库已出现,并通过 Service Catalog 调用site.add端点。

也可以通过终端调用:

$ curl -X POST 'http://localhost:4000/site' -d '{"url": "https://encore.dev"}' { "id": 1, "url": "https://encore.dev" }

5. 记录每次检查结果:monitor 数据库与 check 端点

要在站点宕机(或恢复)时发出通知,必须先记录它上一次的状态。

5.1 添加 checks 表

🥐 同样为monitor服务添加数据库。创建monitor/migrations目录及迁移文件:

-- monitor/migrations/1_create_tables.up.sql -- CREATE TABLE checks ( id BIGSERIAL PRIMARY KEY, site_id BIGINT NOT NULL, up BOOLEAN NOT NULL, checked_at TIMESTAMP WITH TIME ZONE NOT NULL );

每次检查都会向checks表插入一行记录。

5.2 编写 check 端点

🥐 这次改用 Encore 原生的SQLDatabase类(与上一节的 Knex 形成对比,展示两种写法)。创建monitor/check.ts

-- monitor/check.ts -- import { api } from "encore.dev/api"; import { SQLDatabase } from "encore.dev/storage/sqldb"; import { ping } from "./ping"; import { site } from "~encore/clients"; // Check checks a single site. export const check = api( { expose: true, method: "POST", path: "/check/:siteID" }, async (p: { siteID: number }): Promise<{ up: boolean }> => { const s = await site.get({ id: p.siteID }); const { up } = await ping({ url: s.url }); await MonitorDB.exec` INSERT INTO checks (site_id, up, checked_at) VALUES (${s.id}, ${up}, NOW()) `; return { up }; }, ); // Define a database named 'monitor', using the database migrations // in the "./migrations" folder. Encore automatically provisions, // migrates, and connects to the database. export const MonitorDB = new SQLDatabase("monitor", { migrations: "./migrations", });

这里有两个值得注意的 Encore.ts 特性:

  1. ~encore/clients类型安全的服务间调用import { site } from "~encore/clients"是由 Encore 自动生成的客户端引用,让你像调用本地函数一样调用其他服务的端点(site.get),并且全程类型安全、自动集成分布式追踪。这里site.get没有设置expose却仍被调用,正是因为内部网络调用不需要 expose
  2. SQL 模板字符串MonitorDB.exec\...`是 Encore 提供的类型安全 SQL 查询方式,参数通过${}` 插值并以参数化形式传给数据库,天然防止 SQL 注入。

🥐 重启encore run创建monitor数据库。在 Flow 图中可以看到monitorsite服务之间新增的依赖关系。然后调用monitor.check端点(使用上一步得到的 id1),并在 trace 中查看数据库交互。

也可以直接用命令行检查数据库内容:

$ encore db shell monitor psql (14.4, server 14.2) Type "help" for help. monitor=> SELECT * FROM checks; id | site_id | up | checked_at ----+---------+----+------------------------------- 1 | 1 | t | 2022-10-21 09:58:30.674265+00

看到这条记录,说明一切正常。

6. 用 Cron 任务定时检查所有站点

现在要定期检查所有被追踪站点。先把check端点的核心逻辑抽取成可复用的doCheck函数:

-- monitor/check.ts -- import {Site} from "../site/site"; // Check checks a single site. export const check = api( { expose: true, method: "POST", path: "/check/:siteID" }, async (p: { siteID: number }): Promise<{ up: boolean }> => { const s = await site.get({ id: p.siteID }); return doCheck(s); }, ); async function doCheck(site: Site): Promise<{ up: boolean }> { const { up } = await ping({ url: site.url }); await MonitorDB.exec` INSERT INTO checks (site_id, up, checked_at) VALUES (${site.id}, ${up}, NOW()) `; return { up }; }

6.1 新增 checkAll 端点

🥐 在monitor/check.ts中添加checkAll端点,列出所有站点并全部检查一遍(用Promise.all并行执行):

-- monitor/check.ts -- // CheckAll checks all sites. export const checkAll = api( { expose: true, method: "POST", path: "/check-all" }, async (): Promise<void> => { const sites = await site.list(); await Promise.all(sites.sites.map(doCheck)); }, );

6.2 定义每小时触发的 Cron 任务

🥐 定义一个 Cron 任务 自动调用checkAll(作为示例,每小时一次即可):

-- monitor/check.ts -- import { CronJob } from "encore.dev/cron"; // Check all tracked sites every 1 hour. const cronJob = new CronJob("check-all", { title: "Check all sites", every: "1h", endpoint: checkAll, });

对照 CronJob 的源码定义,配置项说明如下:

  • endpoint:要定时调用的 API 端点(必填);
  • every:间隔时长(DurationString,如"1h""30m");
  • schedule:与every二选一,直接写 cron 表达式;
  • title:任务的人类可读标题。

⚠️ 注意:Cron 任务在本地开发运行应用时不会被触发,只有部署到云环境后才生效。这是为了避免本地开发时产生困惑。

6.3 status 端点:聚合展示当前状态

前端需要一个接口来列出所有站点及其当前在线状态。

🥐 创建monitor/status.ts

-- monitor/status.ts -- import { api } from "encore.dev/api"; import { MonitorDB } from "./check"; interface SiteStatus { id: number; up: boolean; checkedAt: string; } // StatusResponse is the response type from the Status endpoint. interface StatusResponse { // Sites contains the current status of all sites, // keyed by the site ID. sites: SiteStatus[]; } // status checks the current up/down status of all monitored sites. export const status = api( { expose: true, path: "/status", method: "GET" }, async (): Promise<StatusResponse> => { const rows = await MonitorDB.query` SELECT DISTINCT ON (site_id) site_id, up, checked_at FROM checks ORDER BY site_id, checked_at DESC `; const results: SiteStatus[] = []; for await (const row of rows) { results.push({ id: row.site_id, up: row.up, checkedAt: row.checked_at, }); } return { sites: results }; }, );

SQL 中的DISTINCT ON (site_id)配合ORDER BY site_id, checked_at DESC,正是"取每个站点最近一次检查记录"的标准写法。这里也展示了MonitorDB.queryqueryRow(后面会用到)这类流式查询 API。

后端完成!打开 http://localhost:4000/ 即可看到配套前端页面。

7. 部署(可选:先让系统真正跑起来)

一个还没部署的系统称不上真正的监控系统。Encore 提供两种部署方式:

方式一:自托管(Self-hosting)

Encore 支持直接从 CLI 构建 Docker 镜像,然后部署到任意自有基础设施。由于应用使用了 SQL 数据库等基础设施资源,需要为 Docker 镜像提供运行时配置。

🥐 在项目根目录创建infra-config.json

{ "$schema": "https://encore.dev/schemas/infra.schema.json", "sql_servers": [ { "host": "my-db-host:5432", "databases": { "monitor": { "username": "my-db-owner", "password": {"$env": "DB_PASSWORD"} }, "site": { "username": "my-db-owner", "password": {"$env": "DB_PASSWORD"} } } } ] }

这些值只是示例,请替换为你真实数据库的地址与凭据。密码通过{"$env": "DB_PASSWORD"}从环境变量注入,避免硬编码。更完整的示例可参考在 DigitalOcean 上部署带 PostgreSQL 的 Encore 应用。

🥐 构建 Docker 镜像:

$ encore build docker uptime:v1.0

该命令会在宿主机上编译应用,并产出一个包含编译后应用的 Docker 镜像。

🥐 将镜像上传到你选择的云厂商并运行。

方式二:Encore Cloud(免费)

Encore Cloud 提供自动化的基础设施与 DevOps 能力,可以部署到免费开发环境,或你自己的 AWS/GCP 账号。

创建账号:如果还没有账号,运行encore app create并在提示时选择Y创建。创建新应用时选择empty app模板,然后把项目文件复制进新应用目录——注意不要替换encore.app文件(它持有连接应用与平台所需的唯一 ID)。

提交代码:Encore 自带 CI/CD,部署流程简单到一次git push(也可以集成 GitHub,详见 CI/CD 文档)。

🥐 部署到 Encore 免费开发云:

$ git add -A . $ git commit -m 'Initial commit' $ git push encore

Encore 会自动构建并测试应用、供给所需基础设施、然后部署到云端。触发部署后,你会得到一个形如https://app.encore.dev/$APP_ID/deploys/...的链接来查看进度。在 Cloud Dashboard 中你还可以查看指标、手动触发 Cron 任务、查看调用链,以及后续接入自己的 AWS/GCP 账号。

🥐 部署完成后,访问https://staging-$APP_ID.encr.app体验真实的 uptime monitor。

8. 用 Pub/Sub 发布站点状态变更事件

一个不会通知你站点宕机的监控系统是没用的。现在为系统添加 Pub/Sub 主题:每当站点从在线变为离线(或反之)时,发布一条消息。

8.1 定义 Topic

🥐 在monitor/check.ts中定义主题:

-- monitor/check.ts -- import { Subscription, Topic } from "encore.dev/pubsub"; // TransitionEvent describes a transition of a monitored site // from up->down or from down->up. export interface TransitionEvent { site: Site; // Site is the monitored site in question. up: boolean; // Up specifies whether the site is now up or down (the new value). } // TransitionTopic is a pubsub topic with transition events for when a monitored site // transitions from up->down or from down->up. export const TransitionTopic = new Topic<TransitionEvent>("uptime-transition", { deliveryGuarantee: "at-least-once", });

查看 Topic 源码 与TopicConfig类型,可以看到:

  • deliveryGuarantee支持"at-least-once"(至少一次,吞吐无限制)与"exactly-once"(精确一次,但吞吐受限:AWS 每主题约 300 msg/s,GCP 每区域至少 3000 msg/s,且订阅延迟更高,建议处理器保持幂等);
  • 还可选orderingAttribute设置消息顺序键,保证相同键的消息按发布顺序投递(本地开发时该项暂不生效)。

8.2 对比前后状态并发布消息

🥐 添加getPreviousMeasurement函数,查询该站点上一次的在线状态:

-- monitor/check.ts -- // getPreviousMeasurement reports whether the given site was // up or down in the previous measurement. async function getPreviousMeasurement(siteID: number): Promise<boolean> { const row = await MonitorDB.queryRow` SELECT up FROM checks WHERE site_id = ${siteID} ORDER BY checked_at DESC LIMIT 1 `; return row?.up ?? true; }

🥐 修改doCheck,仅在状态发生翻转时发布消息:

-- monitor/check.ts -- async function doCheck(site: Site): Promise<{ up: boolean }> { const { up } = await ping({ url: site.url }); // Publish a Pub/Sub message if the site transitions // from up->down or from down->up. const wasUp = await getPreviousMeasurement(site.id); if (up !== wasUp) { await TransitionTopic.publish({ site, up }); } await MonitorDB.exec` INSERT INTO checks (site_id, up, checked_at) VALUES (${site.id}, ${up}, NOW()) `; return { up }; }

🥐 重启encore run并打开本地开发仪表盘的 Flow 架构图,你会看到 Pub/Sub 主题以黑色盒子的形式出现在图中。注意观察:现在监控系统发布消息时并不知道也不关心谁在听——这正是事件驱动架构的松耦合精髓。

9. Slack 通知:订阅主题并发送告警

"真相是,目前还没有人订阅这些消息。" 现在就来修复这个问题。

9.1 创建 slack 服务

🥐 创建slack服务:

$ mkdir slack # Create a new directory in the application root $ touch slack/encore.service.ts
-- slack/encore.service.ts -- import { Service } from "encore.dev/service"; export default new Service("slack");

9.2 用 Secrets 安全存储 Webhook URL

🥐 创建slack/slack.ts

-- slack/slack.ts -- import { api } from "encore.dev/api"; import { secret } from "encore.dev/config"; import log from "encore.dev/log"; export interface NotifyParams { text: string; // the slack message to send } // Sends a Slack message to a pre-configured channel using a // Slack Incoming Webhook (see https://api.slack.com/messaging/webhooks). export const notify = api<NotifyParams>({}, async ({ text }) => { const url = webhookURL(); if (!url) { log.info("no slack webhook url defined, skipping slack notification"); return; } const resp = await fetch(url, { method: "POST", headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ content: text }), }); if (resp.status >= 400) { const body = await resp.text(); throw new Error(`slack notification failed: ${resp.status}: ${body}`); } }); // SlackWebhookURL defines the Slack webhook URL to send uptime notifications to. const webhookURL = secret("SlackWebhookURL");

这里展示了 Encore 的 Secrets 机制。查看 secrets.ts 源码 可知:secret("SlackWebhookURL")返回一个类型安全的可调用对象,每次调用取当前值;Encore 会周期性刷新密钥值。本地开发时如果密钥未设置,会返回空字符串而不报错(方便本地调试);而在云端环境未设置则直接抛错。这样webhookURL()为空时优雅跳过通知的逻辑,正是针对本地场景设计的。

9.3 设置 Secret 并测试

🥐 去一个有创建 Incoming Webhook 权限的 Slack 社区,创建 webhook 后设置为 Encore secret:

$ encore secret set --type dev,local,pr SlackWebhookURL Enter secret value: ***** Successfully updated development secret SlackWebhookURL.

🥐 用 cURL 测试slack.notify端点:

$ curl 'http://localhost:4000/slack.notify' -d '{"text": "Testing Slack webhook"}'

你指定的 Slack 频道应出现Testing Slack webhook消息。

9.4 订阅状态变更事件

🥐 添加 Pub/Sub 订阅者,让 Slack 通知全自动:

-- slack/slack.ts -- import { Subscription } from "encore.dev/pubsub"; import { TransitionTopic } from "../monitor/check"; const _ = new Subscription(TransitionTopic, "slack-notification", { handler: async (event) => { const text = `*${event.site.url} is ${event.up ? "back up." : "down!"}*`; await notify({ text }); }, });

new Subscription(TransitionTopic, "slack-notification", { handler })slack服务与monitor服务解耦:monitor只负责发布事件,slack只负责消费事件并发通知。两者之间唯一的"约定"就是TransitionEvent的消息结构。

10. 部署完整版 Uptime Monitor

现在你的系统已经完整,可以部署了。

自托管

由于新增了基础设施(Pub/Sub 主题、订阅者、Slack 密钥),需要更新infra-config.json,把新的 Pub/Sub 主题与订阅、以及SlackWebhookURL密钥的注入方式都配置进去。

🥐 更新infra-config.json以反映新的基础设施。

🥐 构建镜像并部署:

$ encore build docker uptime:v2.0

🥐 上传镜像到云厂商并运行。

Encore Cloud(免费)

🥐 和之前一样,一行命令完成部署:

$ git add -A . $ git commit -m 'Add slack integration' $ git push encore

🎉 庆祝一下

应用已在云端运行。在 Cloud Dashboard 中按Cmd + K(Mac)或Ctrl + K(Windows/Linux)打开 Command Menu(从这里可以快速访问所有 Cloud Dashboard 功能,例如直接跳到 Service Catalog 中的某个服务、查看指定端点的调用链)。

🥐 在 Command Menu 中输入fireworks并回车,坐下欣赏这场烟火秀吧。

11. 总结

回顾一下,我们用极少的代码完成了一个功能完整的 uptime 监控系统:

  • 构建了三个服务:site(站点管理)、monitor(检查调度)、slack(通知投递);
  • 添加了两个数据库(sitemonitor服务各一个),分别存放被监控站点与检查结果,全部由 Encore 自动供给、迁移、连接;
  • 添加了每小时自动检查所有站点的 Cron 任务;
  • 设置了一个 Pub/Sub 主题,将监控系统与 Slack 通知彻底解耦;
  • 接入 Slack 集成,用 Secrets 安全存放 webhook URL,通过订阅状态变更事件自动发送通知。

这一切只用了 300 多行代码。核心秘诀在于 Encore.ts 把服务定义(Service)、端点(api)、数据库(SQLDatabase+ 迁移)、定时任务(CronJob)、消息总线(Topic/Subscription)和密钥(secret)都变成了声明式的基础设施原语——你描述意图,Encore 负责供给与运维。接下来,你可以基于应用结构、数据库与 Pub/Sub等文档继续扩展,比如加入更精细的告警策略、Telegram/邮件通知渠道,或者把检查频率提高到分钟级。从今往后,再也不必担心网站悄然宕机而无人知晓了。

【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encore

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 19:47:46

湖南关键词优化排名推广避坑指南:新手建站不踩雷

湖南关键词优化排名推广避坑指南:新手建站不踩雷 不会代码想做网站?别急着找外包。很多湖南的中小企业老板或创业者,卡在第一步:想做个官网或商城,但不懂技术,怕被坑。这篇避坑指南,不讲虚的,只讲湖南本地做关键词优化排名推广时,新手最容易交智商税的地方。 一、 明确目标:别被“全站收录”忽悠…

作者头像 李华
网站建设 2026/9/15 19:45:31

用分数阶傅里叶变换(FRFT)实现chirp信号检测与参数估计

在雷达目标检测、水声通信、甚至是生物医学信号分析里&#xff0c;我经常碰到一类“频率随时间线性变化”的信号。这类信号叫chirp&#xff0c;也叫线性调频信号。直观说&#xff0c;它的瞬时频率是一条直线&#xff0c;要么往上扫、要么往下扫。问题在于&#xff0c;常规FFT一…

作者头像 李华
网站建设 2026/9/15 19:43:39

Linux磁盘幽灵空间排查:df满du没满的真相与处理

凌晨两点四十&#xff0c;监控平台的告警把值班手机震醒了。登录服务器一看&#xff0c;根分区或者说某个数据分区使用率已经冲到95%以上&#xff0c;df -h 红得刺眼。但等我跑了一遍 du&#xff0c;整个人都愣住了&#xff1a;系统里所有能看到的文件加起来&#xff0c;离 df …

作者头像 李华
网站建设 2026/9/15 19:43:31

微信小程序仿淘票票源码实战:项目结构、选座与性能优化

简介&#xff1a;一套模仿淘票票APP界面的微信小程序源代码&#xff0c;适合正在学习小程序开发的初中级开发者&#xff0c;以及想参考影票类界面交互与页面流程的爱好者。借助这套代码&#xff0c;可以直观理解小程序中页面结构、逻辑层与样式层的组织方式&#xff0c;无需复杂…

作者头像 李华