Cloudflare开发者平台的全面演进
2026年8月,Cloudflare在开发者平台领域动作频频:从将CI流水线变为TypeScript工作流,到推出Agent Tracing,再到将日处理90亿请求的cdnjs迁移至自有开发者平台,Cloudflare正在从一家CDN公司全面转型为开发者基础设施平台。
这一系列发布共同描绘了一个清晰的愿景:构建一个以Workers为核心、以TypeScript为语言的全栈开发者平台。对于开发者而言,这意味着从边缘计算到CI/CD、从静态资源托管到AI代理可观测性,所有能力都可以在一个平台内完成。
Cloudflare CI:用TypeScript定义CI/CD流水线
从YAML到TypeScript的范式转变
2026年8月17日,Cloudflare发布了cloudflare/ci——一个CI SDK,允许开发者用TypeScript在Cloudflare Workflows之上定义CI流水线。这标志着CI/CD流水线定义方式从声明式配置(YAML)向命令式编程(TypeScript)的转变。
传统CI流水线使用YAML定义,虽然简洁但缺乏表达力——无法使用条件逻辑、循环、函数复用等编程语言特性。TypeScript定义的CI流水线则可以:
核心特性
// cloudflare/ci 流水线定义示例
import { Pipeline, Step } from "@cloudflare/ci";
const pipeline = new Pipeline({
name: "build-and-deploy",
trigger: { on: "push", branches: ["main"] }
});
// 步骤1:安装依赖
pipeline.addStep(new Step({
name: "install",
run: async (ctx) => {
await ctx.exec("npm", ["ci"]);
// 保存依赖缓存,下次构建可复用
await ctx.cache.save("node_modules", {
key: "deps-{{checksum package.json}}"
});
}
}));
// 步骤2:并行执行 lint + test + build(默认并发)
pipeline.addStep(new Step({
name: "lint",
run: async (ctx) => {
await ctx.exec("npm", ["run", "lint"]);
},
concurrent: true // 默认就是true,显式标注
}));
pipeline.addStep(new Step({
name: "test",
run: async (ctx) => {
await ctx.exec("npm", ["test", "--", "--coverage"]);
// 上传覆盖率报告作为构建产物
await ctx.artifacts.upload("coverage/");
},
concurrent: true
}));
pipeline.addStep(new Step({
name: "build",
run: async (ctx) => {
await ctx.exec("npm", ["run", "build"]);
// 保存构建产物快照,用于后续步骤或失败回放
await ctx.snapshot.save("dist/");
},
concurrent: true,
dependsOn: ["install"]
}));
// 步骤3:条件部署
pipeline.addStep(new Step({
name: "deploy",
run: async (ctx) => {
// 只有main分支才部署到生产
if (ctx.branch === "main" && ctx.status === "success") {
await ctx.exec("npx", ["wrangler", "deploy"]);
// 通知部署完成
await ctx.notify({
channel: "deployments",
message: `Deployed ${ctx.commit.sha.slice(0, 7)} to production`
});
}
},
dependsOn: ["lint", "test", "build"]
}));
export default pipeline;关键特性对比
| 特性 | 传统CI(GitHub Actions) | Cloudflare CI |
|------|--------------------------|---------------|
| 流水线定义 | YAML | TypeScript |
| 类型安全 | 无 | 完整TypeScript类型 |
| 步骤并发 | 需显式配置 | 默认并发 |
| 重试机制 | 需手动实现 | 内置持久重试 |
| 状态恢复 | 有限支持 | Sandbox快照缓存 |
| 回放能力 | 不支持 | 支持步骤重放 |
| 运行时 | 临时Runner | Cloudflare Workers |
| 依赖复用 | cache action | 内置缓存 |
持久化重试与回放
Cloudflare CI的核心优势在于持久化执行模型。传统的CI流水线中,一个步骤失败后需要从头重跑整个流水线。Cloudflare CI基于Cloudflare Workflows的持久化能力,提供了:
实践:从GitHub Actions迁移
// 从GitHub Actions迁移到Cloudflare CI
// 原始GitHub Actions workflow(YAML):
// jobs:
// build:
// steps:
// - uses: actions/checkout@v4
// - uses: actions/setup-node@v4
// - run: npm ci
// - run: npm run build
// - run: npm test
// 迁移后的Cloudflare CI流水线
import { Pipeline, Step } from "@cloudflare/ci";
const pipeline = new Pipeline({
name: "ci",
trigger: { on: "push" }
});
// checkout在Cloudflare CI中自动完成
// setup-node使用Sandbox环境中的Node.js
pipeline.addStep(new Step({
name: "install",
run: async (ctx) => {
await ctx.exec("npm", ["ci"]);
await ctx.cache.save("node_modules", {
key: `deps-${ctx.checksum("package.json")}`
});
}
}));
// build和test默认并发执行
pipeline.addStep(new Step({
name: "build",
run: async (ctx) => {
await ctx.exec("npm", ["run", "build"]);
await ctx.snapshot.save("dist/");
},
dependsOn: ["install"]
}));
pipeline.addStep(new Step({
name: "test",
run: async (ctx) => {
await ctx.exec("npm", ["test"]);
await ctx.artifacts.upload("test-results/");
},
dependsOn: ["install"]
}));
// 添加lint步骤(原workflow中没有,迁移时增强)
pipeline.addStep(new Step({
name: "lint",
run: async (ctx) => {
await ctx.exec("npm", ["run", "lint"]);
},
dependsOn: ["install"]
}));
export default pipeline;迁移的核心变化是从声明式YAML转向命令式TypeScript。虽然学习曲线略陡,但带来的类型安全、代码复用和调试便利性是YAML无法比拟的。
Agent Tracing:代理可观测性
功能概述
2026年8月15日,Cloudflare推出了Agent Tracing功能,为在Workers上运行的AI代理添加了追踪能力。新增的追踪跨度(spans)覆盖:
会话可以逐轮(turn by turn)重放,便于调试多轮代理对话。
使用示例
// 在Workers代理中启用Tracing
import { Agent, withTracing } from "@cloudflare/agents";
export class ResearchAgent extends Agent {
async handleRequest(request: Request) {
// withTracing包装器自动记录以下span:
// 1. agent.invocation - 整个请求处理
// 2. model.call - LLM调用
// 3. tool.run - 工具执行
// 4. approval.request - 审批请求(如需要)
return withTracing(this, async (span) => {
span.setAttributes({
"agent.name": "research-agent",
"request.type": "search",
"session.id": request.headers.get("x-session-id")
});
try {
// 模型调用会被自动追踪
const response = await this.model.generate(request.body);
// 记录模型调用的详细信息
span.addEvent("model_response_received", {
tokens_used: response.usage.total_tokens,
model: response.model
});
// 工具调用也会被自动追踪
const result = await this.tools.execute(response.tool_calls);
span.setAttributes({
"tools.executed": response.tool_calls.length,
"result.status": "success"
});
return Response.json(result);
} catch (error) {
span.recordException(error);
span.setStatus({ code: "ERROR", message: error.message });
return Response.json(
{ error: "Agent execution failed" },
{ status: 500 }
);
}
});
}
}注意事项与最佳实践
// 追踪配置最佳实践
import { TracingConfig } from "@cloudflare/agents";
const tracingConfig: TracingConfig = {
// 采样率:生产环境建议10-20%
samplingRate: 0.15,
// 载荷截断设置
maxPayloadLength: 4096, // 限制单条payload长度
// 敏感字段脱敏
redactFields: ["api_key", "password", "token", "ssn"],
// 采样规则
samplingRules: [
// 错误请求100%采样
{ condition: "status == 'ERROR'", rate: 1.0 },
// 慢请求50%采样
{ condition: "duration > 5000", rate: 0.5 },
// 默认10%采样
{ condition: "*", rate: 0.1 }
]
};cdnjs迁移:90亿请求/日的架构重构
迁移背景
Cloudflare将cdnjs——其开源的JavaScript和CSS CDN——迁移到了自有开发者平台。新架构整合了多个Cloudflare组件:
| 组件 | 用途 | 规模/说明 |
|------|------|-----------|
| Workers | 边缘计算 | 全球分布,低延迟响应 |
| R2 | 对象存储 | 包内容存储,零出口费 |
| KV | 键值存储 | 元数据缓存,快速查询 |
| Workflows | 编排 | 发布流水线,版本管理 |
| Queues | 消息队列 | 异步任务处理 |
| Durable Objects | 有状态协调 | 版本一致性保证 |
| Containers | 长时间任务 | 构建与打包 |
迁移在保持包内容、URL和SRI哈希不变的前提下,完成了基础设施的全面重构,日处理请求量达90亿次。这证明了Cloudflare开发者平台具备承载超大规模生产负载的能力。
架构启示
cdnjs的迁移展示了如何用Cloudflare开发者平台组件构建生产级CDN服务:
// cdnjs新架构的核心逻辑(简化版)
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const packagePath = url.pathname;
// 1. 从KV缓存读取元数据
const metadata = await env.PACKAGE_KV.get(
packagePath,
"json"
) as PackageMetadata;
if (!metadata) {
return new Response("Not Found", { status: 404 });
}
// 2. 检查缓存有效性
const cached = await caches.default.match(request);
if (cached) {
return cached;
}
// 3. 从R2获取包内容
const object = await env.PACKAGE_R2.get(metadata.r2Key);
if (!object) {
// 4. 触发异步重建任务(通过Queues)
await env.REBUILD_QUEUE.send({
package: metadata.name,
version: metadata.version
});
return new Response("Package rebuilding", { status: 503 });
}
// 5. 构建响应并设置缓存
const response = new Response(object.body, {
headers: {
"content-type": metadata.contentType,
"cache-control": "public, max-age=31536000, immutable",
"x-package-version": metadata.version
}
});
// 写入边缘缓存
ctx.waitUntil(caches.default.put(request, response.clone()));
return response;
}
};Cache Response Rules:源站后缓存控制
传统Cache Rules的局限
此前,Cloudflare的Cache Rules只能基于请求属性操作——即只能根据URL、Header等请求信息决定是否缓存。这限制了对动态内容的精细缓存控制。
Cache Response Rules的创新
2026年8月15日,Cloudflare引入了Cache Response Rules——一个在源服务器响应之后、内容写入缓存之前运行的规则引擎。它评估源站响应,决定哪些内容应该被缓存。
// Cache Response Rules 配置示例(Wrangler配置)
// wrangler.toml
[cache_response_rules]
[[cache_response_rules.rules]]
name = "cache-api-json"
# 只缓存成功的JSON响应
expression = "response.headers.content_type == 'application/json' && response.status == 200"
cache = true
edge_ttl = 3600 # 边缘缓存1小时
browser_ttl = 60 # 浏览器缓存1分钟
[[cache_response_rules.rules]]
name = "no-cache-auth"
# 带认证头的响应不缓存
expression = "request.headers.authorization != null"
cache = false
[[cache_response_rules.rules]]
name = "cache-static-long"
# 静态资源长期缓存
expression = "response.headers.content_type.startsWith('image/')"
cache = true
edge_ttl = 86400 # 边缘缓存24小时
browser_ttl = 3600 # 浏览器缓存1小时最佳实践:构建全栈应用
// 综合示例:使用Cloudflare开发者平台构建全栈应用
import { Worker, DurableObject } from "cloudflare:workers";
interface Env {
ASSETS_BUCKET: R2Bucket;
PAGE_CACHE: KVNamespace;
API_DO: DurableObjectNamespace;
QUEUE: Queue<JobMessage>;
}
// Workers入口
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
const url = new URL(request.url);
// 静态资源从R2提供
if (url.pathname.startsWith("/assets/")) {
const key = url.pathname.slice(8);
const object = await env.ASSETS_BUCKET.get(key);
if (object) {
return new Response(object.body, {
headers: {
"content-type": object.httpMetadata?.contentType || "application/octet-stream",
"cache-control": "public, max-age=31536000, immutable"
}
});
}
}
// API路由到Durable Object
if (url.pathname.startsWith("/api/")) {
const id = env.API_DO.idFromName("default");
const stub = env.API_DO.get(id);
return stub.fetch(request);
}
// 页面从KV缓存读取
const cached = await env.PAGE_CACHE.get(url.pathname, "text");
if (cached) {
return new Response(cached, {
headers: {
"content-type": "text/html; charset=utf-8",
"cache-control": "public, max-age=60"
}
});
}
// 未命中缓存,触发异步页面生成
await env.QUEUE.send({
type: "generate_page",
path: url.pathname
});
return new Response("Generating page...", { status: 202 });
},
// 队列消费者:异步任务处理
async queue(batch: MessageBatch<JobMessage>, env: Env) {
for (const message of batch.messages) {
if (message.body.type === "generate_page") {
const html = await renderPage(message.body.path);
await env.PAGE_CACHE.put(message.body.path, html, {
expirationTtl: 3600
});
}
message.ack();
}
}
};
// Durable Object 处理有状态API逻辑
export class ApiObject extends DurableObject {
async fetch(request: Request) {
const url = new URL(request.url);
if (url.pathname === "/api/state") {
// 从Durable Object存储读取状态
const state = await this.ctx.storage.get("appState") || {};
return Response.json(state);
}
if (url.pathname === "/api/state" && request.method === "POST") {
const data = await request.json();
await this.ctx.storage.put("appState", data);
return Response.json({ success: true });
}
return new Response("Not Found", { status: 404 });
}
}结语
Cloudflare在2026年8月的这一系列发布——从CI工作流到Agent Tracing再到cdnjs迁移——展示了一个清晰的愿景:构建一个以Workers为核心、以TypeScript为语言的全栈开发者平台。
对于开发者而言,Cloudflare开发者平台已经从"CDN加速"进化为"全栈应用部署平台"。从CI/CD流水线到边缘计算,从静态资源托管到AI代理可观测性,所有能力都可以在同一个平台内、用同一种语言完成。这种统一性带来的开发效率提升是不容忽视的。
值得注意的是,Cloudflare CI目前仍依赖于尚处于私有测试阶段的Artifacts功能,因此其可迁移的经验在于持久化步骤模型的设计理念,而非直接的CI替代方案。但这一设计理念——用TypeScript定义CI流水线、步骤级重试和快照回放——无疑代表了CI/CD工具发展的方向。
💬 评论区 (0)
暂无评论,快来抢沙发吧!