
Encore Backend Framework 代码片段速查手册API、数据库、Cron、PubSub、缓存与密钥的实战用法【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encore导读本文是 Encore 开源仓库encor/encore中面向 Go 后端的速查型技术指南围绕 docs/go/primitives/code-snippets.md 展开当你已经熟悉 Encore 的模型后可以跳过冗长的概念讲解直接复制粘贴这些经过验证的代码片段来搭建 API、SQL 数据库、定时任务、PubSub 事件流、Redis 缓存集群与密钥管理。文章在完整继承原文档全部示例的基础上结合runtimes/go下的真实运行时源码sqldb、cron、pubsub、cache、secrets与cli/cmd/encore/secrets的 CLI 实现补充了参数取值范围、默认值与底层调用链让你既抄得走也读得懂。适用前提以下所有代码片段均以当前仓库runtimes/go的 Go 运行时 API 为准需要你的应用基于 Encore 的 Go Backend Framework 构建并通过encore run启动本地开发环境。APIs定义、调用与裸 HTTP 端点定义 API//encore:api注解在 Encore 中服务就是一个普通的 Go 包。把任意一个函数加上//encore:api注解它就会变成一个由 Encore 统一路由、鉴权、追踪和部署的 API 端点package hello // service name //encore:api public func Ping(ctx context.Context, params *PingParams) (*PingResponse, error) { msg : fmt.Sprintf(Hello, %s!, params.Name) return PingResponse{Message: msg}, nil }关键点包名即服务名package hello意味着这个包是一个名为hello的 Encore 服务public表示公开端点另有private只能被其他服务或平台内部调用外部请求不可直达端点的签名约定为func(ctx context.Context, params *T) (*R, error)params与返回值都可以是结构体指针或简单类型返回值中的error会被 Encore 自动映射为 HTTP 状态码与错误响应请求/响应 schema 会自动生成 OpenAPI 文档与类型安全的客户端见 pkg/clientgen。定义请求与响应 Schema与端点配套的结构体即请求/响应 schema字段名默认采用 Go 风格自动映射为 JSON 字段// PingParams is the request data for the Ping endpoint. type PingParams struct { Name string } // PingResponse is the response data for the Ping endpoint. type PingResponse struct { Message string }调用 API类型安全的函数调用跨服务调用在 Encore 里就是一次普通的 Go 函数调用——编译器会为你生成 RPC 封装无需手动构造 HTTP 请求import encore.app/hello // import service //encore:api public func MyOtherAPI(ctx context.Context) error { resp, err : hello.Ping(ctx, hello.PingParams{Name: World}) if err nil { log.Println(resp.Message) // Hello, World! } return err }提示导入服务包然后像调用普通函数一样调用 API 端点即可。请求会通过 Encore 的服务网格自动完成路由、鉴权、追踪与分布式请求传播。接收 Webhookraw 端点当需要完全控制 HTTP 请求例如接收第三方 Webhook、做自定义路由或接入现有net/http中间件时使用raw端点import net/http // Webhook receives incoming webhooks from Some Service That Sends Webhooks. //encore:api public raw func Webhook(w http.ResponseWriter, req *http.Request) { // ... operate on the raw HTTP request ... }提示与普通端点一样它也会被公开暴露URL 形如https://env-app-id.encr.app/service.Webhookraw 端点直接给你http.ResponseWriter与*http.Request因此可以读取原始 body、请求头写入任意响应内容适合做 Stripe/GitHub 这类第三方 Webhook 接收器。Databases创建、写入与查询 SQL 数据库创建 SQL 数据库并定义迁移导入encore.dev/storage/sqldb调用sqldb.NewDatabase并把结果赋给包级变量即可声明一个数据库sqldb.DatabaseConfig.Migrations指定存放迁移 SQL 文件的目录它就是数据库 schema 的定义方式-- todo/db.go -- package todo // Create the todo database and assign it to the tododb variable var tododb sqldb.NewDatabase(todo, sqldb.DatabaseConfig{ Migrations: ./migrations, }) // Then, query the database using db.QueryRow, db.Exec, etc. -- todo/migrations/1_create_table.up.sql -- CREATE TABLE todo_item ( id BIGSERIAL PRIMARY KEY, title TEXT NOT NULL, done BOOLEAN NOT NULL DEFAULT false -- etc... );补充说明基于 runtimes/go/storage/sqldb/sqldb.go 与 db.go 的源码底层连接池由pgxpool.Pool管理Database结构体中的pool *pgxpool.Pool并通过database/sql兼容层暴露Stdlib()方法可无缝接入期望*sql.DB的第三方库迁移采用版本化 SQL 文件如1_create_table.up.sqlEncore 在本地开发环境自动执行迁移让数据库与代码保持一致每个Database都会自动注入分布式追踪DBQueryStart/DBQueryEnd等 trace 事件你在本地开发仪表盘上可以直接看到每条 SQL 的执行情况。插入数据使用包方法sqldb.Exec底层即Database.Exec执行带占位符参数的 SQL避免 SQL 注入import encore.dev/storage/sqldb // insert inserts a todo item into the database. func insert(ctx context.Context, id, title string, done bool) error { _, err : tododb.Exec(ctx, INSERT INTO todo_item (id, title, done) VALUES ($1, $2, $3) , id, title, done) return err }参数占位符使用 PostgreSQL 风格$1, $2, $3返回的ExecResult可通过RowsAffected()获取受影响行数sqldb.go。查询单行数据使用sqldb.QueryRow查询一行配合Scan将列映射到 Go 变量import encore.dev/storage/sqldb var item struct { ID int64 Title string Done bool } err : tododb.QueryRow(ctx, SELECT id, title, done FROM todo_item LIMIT 1 ).Scan(item.ID, item.Title, item.Done)提示如果QueryRow没有找到匹配行会返回一个错误可通过导入标准库errors包调用errors.Is(err, sqldb.ErrNoRows)判断。ErrNoRows在源码中定义为sql.ErrNoRows见 sqldb.go因此语义与database/sql完全一致。另外数据库服务端报错会被转换为携带Code、Severity、TableName等结构化信息的*sqldb.Error可用sqldb.ErrCode(err)进一步分类处理见 errors.go。Defining a Cron Job定义定时任务使用encore.dev/cron的cron.NewJob定义一个定时任务并把它赋值给包级变量var _ 表示仅为了注册无需持有引用import encore.dev/cron var _ cron.NewJob(welcome-email, cron.JobConfig{ Title: Send welcome emails, Every: 2 * cron.Hour, Endpoint: SendWelcomeEmail, }) //encore:api private func SendWelcomeEmail(ctx context.Context) error { // ... return nil }提示Cron Jobs 不会在本地开发环境中自动执行你需要直接调用目标端点来测试实现。从 runtimes/go/cron/cron.go 可以补充以下重要约束id必须是 kebab-case不超过 63 个字符以字母开头、以字母或数字结尾这个 ID 是任务在平台侧的稳定标识后续重构代码、移动定义位置时Encore 靠它判断还是同一个任务JobConfig中Every与Schedule二选一Every接受cron.Minute/cron.Hour常量构成的间隔且间隔必须能整除 24 小时如10 * cron.Minute、6 * cron.Hour合法7 * cron.Hour不合法编译器会在编译期报错Schedule则接受标准 Cron 表达式Endpoint的签名必须是func(context.Context) error或func(context.Context) (T, error)且不能带其他参数JobConfig的字段在编译期被解析并用于平台侧资源供给因此必须写成常量字面量运行时并不真正执行这段配置。PubSub主题、发布与订阅创建 PubSub Topic用pubsub.NewTopic创建泛型主题Topic[T]T是消息载荷类型主题必须声明为包级变量不能在函数内部创建import encore.dev/pubsub type SignupEvent struct { UserID int } var Signups pubsub.NewTopic*SignupEvent提示无论主题定义在哪个服务任何服务都可以向其发布消息或订阅。配置细节见 runtimes/go/pubsub/internal/types/public.goDeliveryGuarantee是必填字段可选pubsub.AtLeastOnce至少一次投递AWS/GCP 无吞吐限制或pubsub.ExactlyOnce尽力恰好一次投递需注意 ExactlyOnce 只约束投递而非发布若应用逻辑重试导致同一消息发布两次仍会投递两次所以订阅端处理函数最好保持幂等可选OrderingAttribute指定消息属性作为排序键保证相同取值消息按发布顺序投递消息属性通过pubsub-attrstruct tag 声明UserID string \pubsub-attr:user-id本地开发环境中排序键暂时不生效。发布事件Pub调用主题的Publish方法发布消息返回唯一的消息 IDPublish会阻塞直到消息被主题成功接收if _, err : Signups.Publish(ctx, SignupEvent{UserID: id}); err ! nil { return err } if err : tx.Commit(); err ! nil { return err }从 topic.go 可以看到Publish的内部链路先校验ctx将消息属性与 JSON body 序列化自动注入encore_parent_trace_id/encore_ext_correlation_id等关联追踪属性再经由限流器publishLimiter.Wait后调用底层云 Provider 的PublishMessage同时记录PubsubPublishStart/End追踪事件——这意味着发布是可观测的并且会把 trace 上下文自动传递给订阅方。提示如果要从其他服务发布导入该主题的包变量本例中的Signups并调用其Publish即可。订阅事件Sub通过pubsub.NewSubscription以包级变量创建订阅指定要订阅的主题、订阅名与处理函数var _ pubsub.NewSubscription( user.Signups, send-welcome-email, pubsub.SubscriptionConfig[*SignupEvent] { Handler: SendWelcomeEmail, }, ) func SendWelcomeEmail(ctx context.Context, event *SignupEvent) error { ... send email ... return nil }SubscriptionConfig中的Handler是必填字段返回nil表示消息被确认ack不再重投返回非nil错误会触发负确认nack与重试直到达到重试上限。常用可选配置见 types.goMaxConcurrency单个服务实例并发处理的消息数上限负值表示不限制注意该配置对 Encore Cloud 不生效部分云 Provider 会自适应并发AckDeadline处理超时时间默认 30 秒、至少 1 秒超时后消息会被放回订阅MessageRetention未投递消息的保留时长默认 7 天RetryPolicyMinBackoff默认 10 秒/MaxBackoff默认 10 分钟/MaxRetries0时使用默认 100 次重试pubsub.NoRetries立即进入死信队列pubsub.InfiniteRetries永不进入死信。Defining a Cache cluster定义 Redis 缓存集群使用encore.dev/storage/cache的cache.NewCluster声明一个 Redis 缓存集群同样必须赋给包级变量import encore.dev/storage/cache var MyCacheCluster cache.NewCluster(my-cache-cluster, cache.ClusterConfig{ // EvictionPolicy tells Redis how to evict keys when the cache reaches // its memory limit. For typical cache use cases, cache.AllKeysLRU is a good default. EvictionPolicy: cache.AllKeysLRU, })从 runtimes/go/storage/cache/cache.go 可以看到 Encore 支持的全部淘汰策略EvictionPolicy字符串常量常量Redis 策略行为cache.AllKeysLRUallkeys-lru淘汰最久未使用的键默认值多数缓存场景的推荐选择cache.AllKeysLFUallkeys-lfu淘汰最不常使用的键cache.AllKeysRandomallkeys-random随机淘汰任意键cache.VolatileLRUvolatile-lru仅淘汰设置了过期时间的键中最久未使用的cache.VolatileLFUvolatile-lfu仅淘汰设置了过期时间的键中最不常使用的cache.VolatileTTLvolatile-ttl淘汰剩余 TTL 最短的键cache.VolatileRandomvolatile-random在设置了过期时间的键中随机淘汰cache.NoEvictionnoeviction不淘汰任何键内存达到上限时直接返回错误底层客户端基于github.com/go-redis/redis/v8并围绕keyspace KeyPattern 过期策略提供类型安全的读写 API含Miss、KeyExists等可errors.Is判定的哨兵错误对带默认过期时间的 keyspace写操作会通过 Redis 事务管道TxPipeline把命令与过期时间更新合并为原子操作见 cache.go。Secrets定义、设置与使用密钥定义 Secrets在任意服务包中声明一个未导出的、名为secrets的结构体变量字段为string类型字段名即密钥名var secrets struct { GitHubAPIToken string // personal access token for deployments SomeOtherSecret string // some other secret }提示变量必须是未导出的、名为secrets的结构体且所有字段类型必须是string。该结构体由 Encore 编译器特殊识别不会被打包进镜像或提交到仓库。设置 Secret 值通过 Encore CLI 为密钥设置不同环境的值$ encore secret set --type types... secret-name提示types决定该密钥值作用于哪些环境类型用逗号分隔的组合包括production、development、preview和local每个密钥在每个环境类型下只能有一个值。CLI 实现cli/cmd/encore/secrets/set.go提供了更完整的用法环境类型支持别名devdevelopment、prodproduction、pr/ephemeralpreview、local也可用--dev等价于 developmentpreviewlocal或--prod快捷标志还可以用--env environment-name只针对某个具体环境设置交互式输入直接在终端运行命令后CLI 会以隐藏输入提示Enter secret value:管道输入$ encore secret set --type dev,local,pr MySecret my-secret.txt注意会去除值末尾的换行符已存在的密钥/选择器组合会被更新而非重复创建若选择器与已有密钥值冲突CLI 会列出冲突明细。使用 Secrets在代码中直接通过secrets.FieldName读取运行时由 Encore 从平台注入实际值func callGitHub(ctx context.Context) { req, _ : http.NewRequestWithContext(ctx, GET, https:///api.github.com/user, nil) req.Header.Add(Authorization, token secrets.GitHubAPIToken) resp, err : http.DefaultClient.Do(req) // ... handle err and resp }提示密钥名在整个应用中全局唯一如果多个服务使用相同的密钥名运行时它们会收到同一个密钥值。密钥不会出现在构建产物或 Git 历史中CLI 在设置完成后还会触发守护进程的SecretsRefresh以便本地环境立即生效见 set.go。小结与下一步这份速查手册覆盖了 Encore Go Backend Framework 的全部核心构建块API含 raw Webhook 端点、SQL 数据库sqldb的建库/迁移/增查、定时任务cron.NewJob、事件驱动pubsub的 Topic/Subscription、Redis 缓存集群cache.NewCluster与密钥管理secrets结构体 encore secret set。所有片段都可在新项目中直接复制使用并享受 Encore 自动提供的分布式追踪、类型安全调用与云端资源供给。需要深入了解某个主题时可继续查阅仓库内对应文档定义 API、数据库、Cron Jobs、PubSub、缓存、Secrets以及对应运行时实现 runtimes/go/storage 与 runtimes/go/pubsub。【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encore创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考