跳转到内容
搜索文档

使用 Timescale 创建无服务器全球分布式时序 API

最后更新 查看 MarkdownAgent 设置

在本教程中,你将学习在 Workers 上构建 API,用于摄取和查询存储在 Timescale 中的时序数据(Timescale 让 PostgreSQL 在云端更快)。

你将创建并部署一个 Worker 函数,该函数暴露用于摄取数据的 API 路由,并使用 Hyperdrive 从边缘代理数据库连接并维护连接池,避免每个请求都建立新的数据库连接。

你将学习如何:

  • 构建并部署 Cloudflare Worker。
  • 使用 Wrangler CLI 配合 Worker secrets。
  • 部署 Timescale 数据库服务。
  • 使用 Hyperdrive 将 Worker 连接到 Timescale 数据库服务。
  • 查询新 API。

可通过阅读 Timescale 文档 了解更多 Timescale 信息。


1. 创建 Worker 项目

运行以下命令从命令行创建 Worker 项目:

npm 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

2. 准备 Timescale 服务

若创建新服务,请前往 Timescale Console 并按以下步骤操作:

  1. 选择右上角的黑色加号 Create Service(创建服务)
  2. 选择 Time Series(时间序列) 作为服务类型。
  3. 选择所需区域和实例大小。本教程 1 CPU 即可。
  4. 设置服务名称以替换随机生成的名称。
  5. 选择 Create Service(创建服务)
  6. 在右侧展开 Connection Info(连接信息) 对话框并复制 Service URL(服务 URL)
  7. 复制显示的密码。你将无法再次获取。
  8. 选择 I stored my password, go to service overview(我已保存密码,前往服务概览)

若使用先前创建的服务,可在 Timescale Console 中获取服务连接信息:

  1. 选择希望 Hyperdrive 连接的服务(数据库)。
  2. 展开 Connection info(连接信息)
  3. 复制 Service URL(服务 URL)。Service URL 是 Hyperdrive 用于连接的连接字符串,包含数据库主机名、端口号和数据库名称。

按如下方式将密码插入 Service URL(保留 @ 之后的部分不变)

postgres://tsdbadmin:YOURPASSWORD@...

以下章节中将此称为 SERVICEURL

3. 创建 Hypertable

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 将在你摄取和查询数据时管理其余部分。

4. 创建数据库配置

创建新的 Hyperdrive 实例需要:

  • 来自步骤 2SERVICEURL
  • 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 pg

复制以下 Worker 代码,替换 ./src/index.ts 中的当前代码。以下代码:

  1. 使用 Hyperdrive 通过 env.HYPERDRIVE.connectionString 生成的连接字符串直接连接到 Timescale 驱动。
  2. 创建 POST 路由,接受 JSON 读数数组并在一次事务中插入 Timescale。
  3. 创建 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>;

5. 部署 Worker

运行以下命令重新部署 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> 替换为上述部署命令中的子域):

Ingest some databash
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}
]
EOF
Query some datash
curl "https://timescale-api.<YOUR_SUBDOMAIN>.workers.dev/readings?limit=10"

在本教程中,你已学习如何使用 Timescale、Workers、Hyperdrive 和 TypeScript 创建从边缘摄取和查询读数的工作示例。

后续步骤

这篇文档对您有帮助吗?