Encore.go 基础设施原语完全指南:在 Go 代码中声明云基础设施

Encore.go 基础设施原语完全指南:在 Go 代码中声明云基础设施 Encore.go 基础设施原语完全指南在 Go 代码中声明云基础设施【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encoreEncore.go本项目仓库encor/encore把后端应用 99% 会用到的基础设施——SQL 数据库、Pub/Sub 消息、对象存储、缓存、Cron 定时任务与 Secrets——封装为一组类型化的基础设施原语让你直接在 Go 代码中声明它们并通过方法使用。本文以官方文档 Primitives 总览 为骨架结合仓库源码与各原语子文档系统讲解每类原语的定义方式、本地运行行为、云端映射关系以及它们在应用结构中的组织方式。读完本文你将掌握如何用几行声明式的 Go 代码搭建起一套本地可跑、云端可部署的完整后端基础设施。基础设施原语一次声明处处运行Encore.go 提供了一组核心基础设施原语覆盖后端应用最常用的场景SQL 数据库PostgreSQL声明数据库、管理迁移、执行查询云端自动预置为 RDS 或 Cloud SQLPub/Sub发布类型化事件并跨服务订阅AWS 上基于 SNSSQSGCP 上基于 Pub/Sub对象存储存储与托管文件本地开发使用本地文件系统生产环境对应 S3 或 GCS缓存类型化的 Redis 缓存键与值都有结构化类型Cron 任务按固定周期或 Cron 表达式调用 API 端点Secrets按名称在代码中引用密钥由云厂商的密钥管理服务托管并在运行时注入。这些原语全部以包级变量的形式声明在 Go 代码中sqldb.NewDatabase、pubsub.NewTopic、objects.NewBucket、cache.NewCluster、cron.NewJob、secrets结构体并统一通过方法调用使用。声明即模型Encore 通过静态分析读取这些声明构建出整个应用的基础设施模型infrastructure model这个模型同时驱动本地开发与云端预置。本地开发encore run 拉起真实实现当你运行encore run时Encore 会为每个原语启动对应的本地实现原语本地实现SQL 数据库通过 Docker 启动真实的 PostgreSQL见 cli/daemon/sqldb/docker 目录Pub/Sub本地 NSQ 消息代理见 cli/daemon/pubsub/nsq.go对象存储本地文件系统将对象存储在磁盘目录见 cli/daemon/objects缓存本地内存实现的 Redis约 100 个键上限、随机驱逐见 miniredis 与 cli/daemon/redis/redis.go这种本地跑真东西的设计意味着你在本地验证过的代码部署到云端时行为一致不会出现本地模拟器可以、生产环境报错的落差。云端环境两种部署路径进入云端后你有两种选择使用 Encore Cloud本地用到的同一份声明会被用来在你的 AWS 或 GCP 账号中预置对应的托管服务RDS、SNSSQS、S3 等。云端映射的完整清单见平台基础设施文档。自行管理基础设施可以用 Terraform 或其他工具自行预置基础设施再通过基础设施配置文件告诉 Encore 指向已有的资源。两种路径下生产环境中的资源正是你的代码所请求的资源——不多不少。面向开发者与 AI Agent 的标准工具箱Encore 的基础设施原语集合意图是构建一套高效的开发工作流——尤其是面向 AI 编码 Agent 的工作流。几乎任何后端问题都可以通过组合这一小套、被充分理解的构建块来解决人类开发者与 Agent 都不需要在每个任务中去评估几十个相互竞争的库或为每个任务拼装定制的基础设施你只需从一个稳定、类型化的词汇表中选择而这个词汇表直接映射到生产环境的云资源基础设施构建块完整捕获了所用基础设施资源的语义因此你可以从单一事实来源代码中的声明出发推理整个技术栈。这正是 Encore 应用模型的核心价值对 AI Agent 而言声明式 类型化 语义完备意味着工具可以安全、可预测地操作基础设施。应用构建块组织代码的结构原语在介绍数据、异步与配置原语之前先看结构原语——它们决定了 Encore 应用如何组织代码。App StructureMonorepo 与单体/微服务Encore 采用monorepo设计官方建议整个后端应用使用一个 Encore 应用。这能让 Encore 构建出覆盖全应用的模型是分布式追踪与 Encore Flow 等特性的基础。对于大型应用可以按多个 system 拆分。Encore 对单体 vs 微服务不预设立场但它让你用单体式开发体验来构建微服务跨服务API 调用自动获得 IDE 自动补全与跨服务类型安全。在 Encore Cloud 创建 AWS/GCP 环境时你还能配置是否将多个服务合并进同一个进程Process Allocation以便在小规模时提升效率或让服务就近部署见环境文档。一个典型的应用目录结构如下详见 App Structure 文档/my-app ├── encore.app // 及其他顶层项目文件 ├── hello // hello 服务一个 Go 包 │ ├── migrations // hello 服务的数据库迁移目录 │ │ └── 1_create_table.up.sql │ ├── hello.go // hello 服务代码 │ └── hello_test.go // hello 服务测试 └── world // world 服务一个 Go 包 └── world.go服务内部还可以使用子包sub-package组织组件与辅助函数子包可以任意嵌套但子包不能定义 API——只有服务包本身可以。此外大型应用可以按业务域拆分为多个system如 Trello 应用的 trello / usr / premium 三个 systemsystem 只是目录层面的逻辑分组对 Encore 而言有意义的仍是包含服务的 Go 包拆分 system 不需要复杂重构。Services一个 Go 包即一个服务在 Encore 中定义服务 在普通 Go 包中定义至少一个 API包名即服务名见 Services 文档。构建微服务架构因此变得异常简单——在应用中创建多个 Go 包即可。Encore 会在应用启动时自动生成初始化所有基础设施资源的main函数你不需要写main。如果想自定义服务初始化行为可以通过服务结构体service structs实现。Defining APIs从普通函数到类型安全端点定义 API 只需给函数加上//encore:api注解Encore 在编译期自动生成路由、校验与序列化样板代码见 Defining APIs 文档package hello // 服务名 //encore:api public func Ping(ctx context.Context, params *PingParams) (*PingResponse, error) { msg : fmt.Sprintf(Hello, %s!, params.Name) return PingResponse{Message: msg}, nil }访问控制有三种public互联网可访问、private仅应用内服务与 Cron 任务可调用、auth公开但要求有效认证。请求/响应函数签名始终包含ctx context.Context与error返回值Encore 由此通过静态分析理解所有 API 的请求与响应结构进而自动生成 API 文档、类型安全客户端等。进阶内容还包括路径参数:name、*wildcard、fallback 路由、header/cookie/query/body 参数映射、option.Option[T]可选类型以及用encore:sensitive标记敏感字段以在追踪中自动脱敏等能力。API Calls 与进阶 API 风格跨服务调用另一个服务的 API 就像调用普通类型化函数本地在进程内完成生产环境自动走网络见 API Calls。更进阶的 API 风格可参考 Raw Endpoints、Service Structs 与 API Errors。数据与存储SQL Databases声明、迁移、查询Encore 原生支持PostgreSQL并把 SQL 数据库视为逻辑资源详见 SQL Databases 文档。创建数据库导入encore.dev/storage/sqldb调用sqldb.NewDatabase并赋值给包级变量对应运行时实现见 runtimes/go/storage/sqldb/pkgfn.gopackage todo // 创建 todo 数据库并赋值给 tododb 变量 var tododb sqldb.NewDatabase(todo, sqldb.DatabaseConfig{ Migrations: ./migrations, })数据库必须在 Encore 服务内创建且通过DatabaseConfig.Migrations指向迁移文件目录来定义 schema。本地运行encore run时Encore 会自动用 Docker 创建数据库需要先安装并运行 Docker如果应用已在运行新增数据库后需停止并重启encore run。迁移约定迁移文件放在服务包内的migrations目录文件名必须为number_name.up.sql编号以数字加下划线开头且必须递增如1_create_table.up.sql、2_add_field.up.sql也可以加前导零如0001_migration.up.sql。Encore 自动处理up迁移down迁移需手动执行。首个迁移通常定义初始表结构CREATE TABLE todo_item ( id BIGSERIAL PRIMARY KEY, title TEXT NOT NULL, done BOOLEAN NOT NULL DEFAULT false );查询与写入接口与标准库database/sql类似。写入可用tododb.Exec(ctx, INSERT INTO ... VALUES ($1,$2,$3), id, title, done)读取可用tododb.QueryRow(ctx, SELECT id, title, done FROM todo_item LIMIT 1).Scan(item.ID, item.Title, item.Done)查询无结果时用errors.Is(err, sqldb.ErrNoRows)判断。云端预置策略production环境通过云厂商的托管 SQL 数据库服务预置development环境则预置为带持久化磁盘的 Kubernetes Deployment。各厂商各环境类型的具体预置内容见基础设施文档。CLI 连接数据库encore help db查看更多encore db shell database-name [--envname]打开 psql shell默认只读可用--write、--admin、--superuser提升权限不传--env默认连本地环境encore db conn-uri database-name [--envname]输出连接字符串云端环境的连接串是临时的encore db proxy [--envname]启动本地代理转发到指定环境中的数据库。迁移错误处理迁移失败时 Encore 会回滚云端部署失败会中止部署。Encore 用schema_migrations表记录迁移版本version与dirty两列可以通过UPDATE schema_migrations SET version version - 1;重跑上一个迁移。encore_services角色Encore 用共享数据库角色encore_services桥接跑迁移的角色与运行时连接数据库的服务角色——运行迁移的所有角色与运行时服务使用的所有角色都被授予encore_services。因此迁移脚本中授予encore_services的任何权限运行时服务角色都会继承。仓库实现见 cli/daemon/sqldb/cluster.go其中GRANT encore_services TO ...正是这一机制的落地。典型用法是物化视图迁移中创建专用 owner 角色并授予encore_services运行时通过SET ROLE matview_owner; REFRESH MATERIALIZED VIEW my_view; RESET ROLE;刷新。若想恢复旧版迁移与运行时共用同一数据库账号的行为可设置环境变量ENCOREDEBUGsqldbrolelegacy仅为向后兼容不建议新应用使用。Object Storage文件与无结构化数据对象存储用于存放文件与无结构化数据最知名的实现是 Amazon S3其语义被所有主流云厂商支持详见 Object Storage 文档。Encore 提供云无关 API支持 S3、GCS 及任何 S3 兼容实现如 DigitalOcean Spaces、MinIO并自动获得全部操作的追踪与插桩、本地开发时对象落在本地文件系统、以及测试时使用内存后端。创建 Bucketbuckets 必须是包级变量不能建在函数内可在任意服务中通过变量引用访问package user import encore.dev/storage/objects var ProfilePictures objects.NewBucket(profile-pictures, objects.BucketConfig{ Versioned: false, })上传/下载用Upload方法拿到 writer写完调用Close完成取消 context 或调用Abort中止Download返回 reader。Upload还支持objects.WithUploadAttrs设置属性与objects.WithPreconditions对象已存在时拒绝上传等选项Download支持objects.WithVersion下载指定版本。列出、删除与属性List(ctx, objects.Query{})返回(error, *objects.ListEntry)迭代器可用range遍历Query可限制数量或按 key 前缀过滤Remove删除对象未找到时返回objects.ErrObjectNotFoundAttrs获取大小、Content-Type、ETag 等属性另有便捷的Exists判断对象是否存在。公开 Bucket设置Public: true后对象可直接通过 HTTP/HTTPS 无认证访问适合静态资源。用PublicURL获取公开 URL自托管时的公开 bucket 配置见基础设施配置文档Encore Cloud 部署时会自动配置公开访问并接入 CDN。BucketRef 权限引用Encore 通过静态分析确定每个服务访问了哪些 bucket、执行了哪些操作据此预置基础设施并配置 IAM 权限。因此*objects.Bucket变量不能随意传递需要用objects.BucketRef获取可在任意地方传递的引用——引用必须在服务内声明且须预先声明所需权限objects.Downloader、Uploader、Lister、Attrser、Remover、SignedDownloader、SignedUploader多权限可通过接口内嵌组合便捷接口objects.ReadWriter提供全部读写权限。底层实现见 runtimes/go/storage/objects/objects.go。签名 URLSignedUploadURL/SignedDownloadURL生成限定期限、绑定单一文件名的 URL持有者无需额外认证即可上传/下载。适合把大文件的流量直接从 API 服务分流到存储桶代价是客户端侧流程更复杂。注意除非内容是私有的否则优先用PublicURL走 CDN性能和成本通常更优。Caching类型安全的 Redis 缓存缓存是分布式系统中降低延迟、避免重复昂贵计算的高速存储层详见 Caching 文档。Encore 的 Caching API 基于 Redis云无关且声明式部署时自动预置基础设施。缓存集群Cache Cluster应用中定义的每个缓存集群会被预置为独立的 Redis 实例让你精确控制哪些服务共享集群、哪些独立。起步阶段官方建议所有服务共享一个集群import encore.dev/storage/cache var MyCacheCluster cache.NewCluster(my-cache-cluster, cache.ClusterConfig{ // 内存达到上限时的驱逐策略典型缓存场景推荐 AllKeysLRU EvictionPolicy: cache.AllKeysLRU, })Keyspace每个 keyspace 有 Key 类型与 Value 类型Key 类型结合KeyPattern生成 Redis 键。例如按用户 ID 做请求限流var RequestsPerUser cache.NewIntKeyspaceauth.UID, })Key 也可以是 structKeyPattern: requests/:UserID/:ResourcePathEncore 在编译期保证所有 struct 字段都出现在KeyPattern中且占位符都是合法字段名同时保证同一集群内各 keyspace 的KeyPattern互不冲突避免多服务共享集群时意外覆盖缓存值。操作与测试基础 keyspace 有NewStringKeyspace、NewIntKeyspaceint64、NewFloatKeyspace、NewStructKeyspace进阶的有NewSetKeyspace集合与NewListKeyspace有序列表。测试时每个测试有独立的内存缓存天然隔离无需手动清理本地开发则使用内存版 Redis上限约 100 个键超出后随机驱逐以模拟缓存的易失性该行为可能会变化不应作为依赖。异步工作Pub/Sub事件驱动的解耦Pub/Sub 让服务通过广播事件异步通信是提升可靠性与响应速度、解耦服务的利器详见 Pub/Sub 文档。核心是Topic发布事件的命名通道必须声明为包级变量主题创建后可被任何服务发布与订阅。package user import encore.dev/pubsub type SignupEvent struct{ UserID int } var Signups pubsub.NewTopic*SignupEvent投递保证AtLeastOnce至少一次事件对每个订阅至少投递一次失败会重试订阅处理器必须幂等可用数据库记录是否已处理或让动作本身幂等ExactlyOnce恰好一次基础设施层面尽量降低重投概率但极端网络情况下仍可能重投Two Generals Problem关键正确性场景仍建议幂等设计。且ExactlyOnce不做发布侧去重——同一消息Publish两次就会被投递两次。开启后云厂商有吞吐限制AWS 主题约 300 条/秒GCP 区域内所有主题至少 3000 条/秒。有序主题默认主题无序吞吐更高通过OrderingAttribute指定事件类型顶层字段带pubsub-attrtag后同一字段值的消息按发布顺序投递给同一订阅者。注意有序主题有队头阻塞风险且OrderingAttribute在本地环境当前不生效吞吐限制为 AWS 300 条/秒、GCP 每个排序键 1MBps。发布与订阅发布即调用Signups.Publish(ctx, SignupEvent{UserID: id})返回消息 ID。订阅用pubsub.NewSubscription创建包级变量每个订阅需要主题、主题内唯一的名字以及至少包含Handler的配置var _ pubsub.NewSubscription( user.Signups, send-welcome-email, pubsub.SubscriptionConfig[*SignupEvent]{ Handler: SendWelcomeEmail, }, )同一主题的多个订阅彼此独立接收事件互不影响处理器ctx在到达AckDeadline默认 30 秒时被取消。使用服务结构体做依赖注入时可用pubsub.MethodHandler((*Service).MethodName)把方法定义为处理器。SubscriptionConfig的字段必须是编译期常量不能是函数调用结果以便 Encore 理解订阅的精确需求来预置基础设施。处理器返回错误时按重试策略重试超过MaxRetries后进入死信队列DLQ修复后可手动释放重投。TopicRef 引用与 BucketRef 同理pubsub.TopicRef[pubsub.Publisher[*SignupEvent]](Signups)允许把主题引用自由传递给库代码或注入服务结构体但声明必须在服务内且权限需预先声明。测试测试用特殊实现订阅不会被发布事件触发可独立测试发布方、发布产生的消息 ID 按顺序确定、各测试完全隔离支持并行测试。用et.Topic(Signups).PublishedMessages()获取测试期间发布的消息进行断言见 runtimes/go/pubsub/internal/test/topic.go。一致性数据库写入与消息发布无法原子化时可参考事务性发件箱Transactional Outbox模式保证服务间一致性。为什么要用 Pub/Sub对比纯 API 调用——用户注册时同步调 email、analytics 服务若邮件服务耗时 3 秒则响应也要等 3 秒且任一下游故障都会影响注册改用 Pub/Sub 后注册只需写库 发布事件立即响应用户email 与 analytics 并行消费互不影响新增关注注册事件的系统也无需改动 user 服务。这正是降低故障爆炸半径、反转服务依赖的价值所在。Cron Jobs声明式定时任务Cron Jobs 用于周期性、可重复的任务声明后 Encore 自动按计划调用你指定的 API调度、监控与执行都由 Encore 管理无需维护基础设施详见 Cron Jobs 文档。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.NewJob的第一个参数是唯一 ID用于在代码重构、移动定义位置时仍然识别同一个任务。使用要点Cron 任务在本地开发与 Preview 环境不执行可手动调用该 API 测试行为Encore Cloud Free Tier 上 Cron 执行每小时最多一次且精确分钟随机需要更高频率或指定分钟需部署到自己的云支持 public 与 private API端点必须幂等网络条件下可能被多次调用端点不能带请求参数签名必须是func(context.Context) error或func(context.Context) (*T, error)。调度方式Every字段按周期执行从午夜UTC开始全天运行间隔必须能整除 24 小时如10 * cron.Minute、6 * cron.Hour合法7 * cron.Hour不合法编译器会报错。更复杂的调度用Schedule字段支持完整的 Cron 表达式时间为 UTC例如每月 15 日凌晨 4 点Schedule: 0 4 15 * *。配置Secrets 安全存储把 API 密钥、数据库密码、私钥写进源码是极度危险的常见错误。Encore 内置的 secrets 管理器让你安全地存储密钥并在程序里像普通变量一样使用详见 Secrets 文档。定义创建非导出的secrets结构体字段全部为string类型var secrets struct { SSHPrivateKey string // ed25519 私钥用于 SSH 服务器 GitHubAPIToken string // 部署用的个人访问令牌 // ... }Encore 编译器会检查所有 secret 在运行/部署前都已设置缺失则编译报错。之后就能像普通变量一样使用例如req.Header.Add(Authorization, token secrets.GitHubAPIToken)。注意secret 键名在整个应用中全局唯一多个服务使用同名 secret 会拿到相同的值。存储值Encore Cloud 仪表盘Settings → Secrets可创建、保存并按环境配置不同值CLIencore secret set --type types secret-nametypes是环境类型列表逗号分隔的production、development、preview、local简写prod、dev、pr例如encore secret set --type prod SSHPrivateKey、encore secret set --type dev,preview,local GitHubAPIToken按环境设置encore secret set --env env-name secret-name为特定环境设置值特定环境的值优先于环境类型的值。每个 secret 对每种环境类型只能有一个值若要覆盖某环境类型下的单个环境需先在 Secrets Manager 中编辑移除该环境类型再新增。存储原理Encore 使用 GCP 的 KMS 加密存储 secret。生产/自有云在你的 GCP/AWS 账号中预置 secrets managerKMS 或 AWS Secrets Manager复制 secret 后以环境变量注入容器本地encore run时自动把 secret 复制到开发者机器Encore Cloud 的开发环境底层是 GCP走 GCP Secrets Manager。本地覆盖encore secret set设置的值会自动同步给同一应用的所有开发者如需只在本机覆盖在应用根目录与encore.app同级创建.secrets.local.cueGitHubAPIToken: my-local-override-token SSHPrivateKey: custom-ssh-private-key原语如何映射到你的云Encore 读取你的原语声明构建应用的基础设施模型。这个模型同时驱动本地开发与云端预置——你生产环境使用的资源就是代码请求的资源不多不少。这条声明 → 模型 → 预置的链路在仓库源码中清晰可见各原语的运行时 API 定义集中在 runtimes/go/storage/sqldb/pkgfn.go、runtimes/go/storage/objects/objects.go、runtimes/go/storage/cache/pkgfn.go、runtimes/go/pubsub/pkgfn.go本地实现由 cli/daemon 下的 sqldb、objects、pubsub、redis 等模块提供云端基础设施的完整映射AWS/GCP 上各原语分别创建哪些资源见平台基础设施文档。掌握这套原语后你可以把基础设施当作代码的一部分来思考和演进修改声明、encore run本地验证、部署后由 Encore 负责把声明变成真实云资源。无论是单体起步还是微服务扩展无论是人工开发还是 AI Agent 辅助这套稳定、类型化、语义完整的词汇表都是整个应用架构的单一事实来源。【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encore创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考