在本教程中,你将学习在 Workers 上构建 API,用于摄取和查询存储在 Timescale ↗ 中的时序数据(Timescale 让 PostgreSQL 在云端更快)。
你将创建并部署一个 Worker 函数,该函数暴露用于摄取数据的 API 路由,并使用 Hyperdrive 从边缘代理数据库连接并维护连接池,避免每个请求都建立新的数据库连接。
你将学习如何:
- 构建并部署 Cloudflare Worker。
- 使用 Wrangler CLI 配合 Worker secrets。
- 部署 Timescale 数据库服务。
- 使用 Hyperdrive 将 Worker 连接到 Timescale 数据库服务。
- 查询新 API。
可通过阅读 Timescale 文档 ↗ 了解更多 Timescale 信息。
运行以下命令从命令行创建 Worker 项目:
npm create cloudflare@latest -- timescale-apiyarn create cloudflare timescale-apipnpm create cloudflare@latest timescale-api进行设置时,请选择以下选项:
- 对于 What would you like to start with?,选择
Hello World example。 - 对于 Which template would you like to use?,选择
Worker only。 - 对于 Which language do you want to use?,选择
TypeScript。 - 对于 Do you want to use git for version control?,选择
Yes。 - 对于 Do you want to deploy your application?,选择
No(部署前我们还会做一些修改)。
记下应用部署到的 URL。配置 GitHub webhook 时将用到。
进入刚创建的 Worker 项目目录:
cd timescale-api若创建新服务,请前往 Timescale Console ↗ 并按以下步骤操作:
- 选择右上角的黑色加号 Create Service(创建服务)。
- 选择 Time Series(时间序列) 作为服务类型。
- 选择所需区域和实例大小。本教程 1 CPU 即可。
- 设置服务名称以替换随机生成的名称。
- 选择 Create Service(创建服务)。
- 在右侧展开 Connection Info(连接信息) 对话框并复制 Service URL(服务 URL)。
- 复制显示的密码。你将无法再次获取。
- 选择 I stored my password, go to service overview(我已保存密码,前往服务概览)。
若使用先前创建的服务,可在 Timescale Console ↗ 中获取服务连接信息:
- 选择希望 Hyperdrive 连接的服务(数据库)。
- 展开 Connection info(连接信息)。
- 复制 Service URL(服务 URL)。Service URL 是 Hyperdrive 用于连接的连接字符串,包含数据库主机名、端口号和数据库名称。
按如下方式将密码插入 Service URL(保留 @ 之后的部分不变):
postgres://tsdbadmin:YOURPASSWORD@...以下章节中将此称为 SERVICEURL。
Timescale 允许你将常规 PostgreSQL 表转换为 hypertables ↗,用于处理时序、事件或分析数据。完成此更改后,Timescale 将无缝管理 hypertable 的分区,并允许你应用压缩或连续聚合等其他功能。
使用上一步复制的 Service URL(已嵌入密码)连接到 Timescale 数据库。
若使用默认 PostgreSQL CLI 工具 psql ↗ 连接,可如下运行 psql(替换上一步的 Service URL)。也可使用 PgAdmin ↗ 等图形工具连接。
psql <SERVICEURL>连接后,粘贴以下 SQL 创建表:
CREATE TABLE readings(
ts timestamptz DEFAULT now() NOT NULL,
sensor UUID NOT NULL,
metadata jsonb,
value numeric NOT NULL
);
SELECT create_hypertable('readings', 'ts');Timescale 将在你摄取和查询数据时管理其余部分。
创建新的 Hyperdrive 实例需要:
- 来自步骤 2 的 SERVICEURL。
- Hyperdrive 服务名称。本教程使用 hyperdrive。
Hyperdrive 使用 create 命令和 --connection-string 参数传递此信息。按如下运行:
npx wrangler hyperdrive create hyperdrive --connection-string="SERVICEURL"此命令输出 Hyperdrive ID。现在可在 Wrangler 配置中绑定 Hyperdrive 配置,将内容替换为以下内容:
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "timescale-api",
"main": "src/index.ts",
// Set this to today's date
"compatibility_date": "2026-08-17",
"compatibility_flags": [
"nodejs_compat"
],
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "your-id-here"
}
]
}"$schema" = "./node_modules/wrangler/config-schema.json"
name = "timescale-api"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-17"
compatibility_flags = [ "nodejs_compat" ]
[[hyperdrive]]
binding = "HYPERDRIVE"
id = "your-id-here"将 Postgres 驱动安装到 Worker 项目:
npm i pgyarn add pgpnpm add pgbun add pg复制以下 Worker 代码,替换 ./src/index.ts 中的当前代码。以下代码:
- 使用 Hyperdrive 通过
env.HYPERDRIVE.connectionString生成的连接字符串直接连接到 Timescale 驱动。 - 创建
POST路由,接受 JSON 读数数组并在一次事务中插入 Timescale。 - 创建
GET路由,接受limit参数并返回最新读数。可改编为按 ID 或时间戳过滤。
import { Client } from "pg";
export interface Env {
HYPERDRIVE: Hyperdrive;
}
export default {
async fetch(request, env, ctx): Promise<Response> {
// Create a new client on each request. Hyperdrive maintains the underlying
// database connection pool, so creating a new client is fast.
const client = new Client({
connectionString: env.HYPERDRIVE.connectionString,
});
await client.connect();
const url = new URL(request.url);
// Create a route for inserting JSON as readings
if (request.method === "POST" && url.pathname === "/readings") {
// Parse the request's JSON payload
const productData = await request.json();
// Write the raw query. You are using jsonb_to_recordset to expand the JSON
// to PG INSERT format to insert all items at once, and using coalesce to
// insert with the current timestamp if no ts field exists
const insertQuery = `
INSERT INTO readings (ts, sensor, metadata, value)
SELECT coalesce(ts, now()), sensor, metadata, value FROM jsonb_to_recordset($1::jsonb)
AS t(ts timestamptz, sensor UUID, metadata jsonb, value numeric)
`;
const insertResult = await client.query(insertQuery, [
JSON.stringify(productData),
]);
// Collect the raw row count inserted to return
const resp = new Response(JSON.stringify(insertResult.rowCount), {
headers: { "Content-Type": "application/json" },
});
return resp;
// Create a route for querying within a time-frame
} else if (request.method === "GET" && url.pathname === "/readings") {
const limit = url.searchParams.get("limit");
// Query the readings table using the limit param passed
const result = await client.query(
"SELECT * FROM readings ORDER BY ts DESC LIMIT $1",
[limit],
);
// Return the result as JSON
const resp = new Response(JSON.stringify(result.rows), {
headers: { "Content-Type": "application/json" },
});
return resp;
}
},
} satisfies ExportedHandler<Env>;运行以下命令重新部署 Worker:
npx wrangler deploy应用现已上线,可通过 timescale-api.<YOUR_SUBDOMAIN>.workers.dev 访问。确切 URI 将在刚运行的 wrangler 命令输出中显示。
部署后,可使用 Cloudflare Worker 与 Timescale IoT 读数数据库交互。由于使用 Cloudflare Hyperdrive 从边缘连接,边缘连接将更快。
现在可使用 Cloudflare Worker 向 readings 表插入新行。要测试此功能,向 Worker 的 URL 发送带有 /readings 路径的 POST 请求,并附带包含新产品数据的 JSON 负载:
[
{ "sensor": "6f3e43a4-d1c1-4cb6-b928-0ac0efaf84a5", "value": 0.3 },
{ "sensor": "d538f9fa-f6de-46e5-9fa2-d7ee9a0f0a68", "value": 10.8 },
{ "sensor": "5cb674a0-460d-4c80-8113-28927f658f5f", "value": 18.8 },
{ "sensor": "03307bae-d5b8-42ad-8f17-1c810e0fbe63", "value": 20.0 },
{ "sensor": "64494acc-4aa5-413c-bd09-2e5b3ece8ad7", "value": 13.1 },
{ "sensor": "0a361f03-d7ec-4e61-822f-2857b52b74b3", "value": 1.1 },
{ "sensor": "50f91cdc-fd19-40d2-b2b0-c90db3394981", "value": 10.3 }
]本教程省略 ts(时间戳)和 metadata(JSON blob),因此它们将分别设为 now() 和 NULL。
发送 POST 请求后,也可向 Worker 的 URL 发送带有 /readings 路径的 GET 请求。设置 limit 参数以控制返回记录数量。
若已安装 curl,可使用以下命令测试(将 <YOUR_SUBDOMAIN> 替换为上述部署命令中的子域):
curl --request POST --data @- 'https://timescale-api.<YOUR_SUBDOMAIN>.workers.dev/readings' <<EOF
[
{ "sensor": "6f3e43a4-d1c1-4cb6-b928-0ac0efaf84a5", "value":0.3},
{ "sensor": "d538f9fa-f6de-46e5-9fa2-d7ee9a0f0a68", "value":10.8},
{ "sensor": "5cb674a0-460d-4c80-8113-28927f658f5f", "value":18.8},
{ "sensor": "03307bae-d5b8-42ad-8f17-1c810e0fbe63", "value":20.0},
{ "sensor": "64494acc-4aa5-413c-bd09-2e5b3ece8ad7", "value":13.1},
{ "sensor": "0a361f03-d7ec-4e61-822f-2857b52b74b3", "value":1.1},
{ "sensor": "50f91cdc-fd19-40d2-b2b0-c90db3394981", "metadata": {"color": "blue" }, "value":10.3}
]
EOFcurl "https://timescale-api.<YOUR_SUBDOMAIN>.workers.dev/readings?limit=10"在本教程中,你已学习如何使用 Timescale、Workers、Hyperdrive 和 TypeScript 创建从边缘摄取和查询读数的工作示例。
- 了解更多Hyperdrive 工作原理。
- 了解更多 Timescale ↗ 信息。
- 参阅故障排除指南 调试常见问题。