encore-go-infrastructure
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseEncore Go Infrastructure Declaration
Encore Go 基础设施声明
Instructions
说明
Encore Go uses declarative infrastructure - you define resources as package-level variables and Encore handles provisioning:
- Locally () - Encore runs infrastructure in Docker (Postgres, Redis, etc.)
encore run - Production - Deploy via Encore Cloud to your AWS/GCP, or self-host using generated infrastructure config
Encore Go 采用声明式基础设施——你将资源定义为包级变量,Encore 会负责资源部署:
- 本地环境()——Encore 在 Docker 中运行基础设施(Postgres、Redis 等)
encore run - 生产环境——通过 Encore Cloud 部署到你的 AWS/GCP,或使用生成的基础设施配置进行自托管
Critical Rule
核心规则
All infrastructure must be declared at package level, not inside functions.
所有基础设施必须在包级别声明,不能在函数内部。
Databases (PostgreSQL)
数据库(PostgreSQL)
go
package user
import "encore.dev/storage/sqldb"
// CORRECT: Package level
var db = sqldb.NewDatabase("userdb", sqldb.DatabaseConfig{
Migrations: "./migrations",
})
// WRONG: Inside function
func setup() {
db := sqldb.NewDatabase("userdb", sqldb.DatabaseConfig{...})
}go
package user
import "encore.dev/storage/sqldb"
// CORRECT: Package level
var db = sqldb.NewDatabase("userdb", sqldb.DatabaseConfig{
Migrations: "./migrations",
})
// WRONG: Inside function
func setup() {
db := sqldb.NewDatabase("userdb", sqldb.DatabaseConfig{...})
}Migrations
迁移
Create migrations in the directory:
migrations/user/
├── user.go
├── db.go
└── migrations/
├── 1_create_users.up.sql
└── 2_add_email_index.up.sqlMigration naming:
{number}_{description}.up.sql在 目录中创建迁移文件:
migrations/user/
├── user.go
├── db.go
└── migrations/
├── 1_create_users.up.sql
└── 2_add_email_index.up.sql迁移文件命名规则:
{编号}_{描述}.up.sqlPub/Sub
发布/订阅(Pub/Sub)
Topics
主题
go
package events
import "encore.dev/pubsub"
type OrderCreatedEvent struct {
OrderID string `json:"order_id"`
UserID string `json:"user_id"`
Total int `json:"total"`
}
// Package level declaration
var OrderCreated = pubsub.NewTopic[*OrderCreatedEvent]("order-created", pubsub.TopicConfig{
DeliveryGuarantee: pubsub.AtLeastOnce,
})go
package events
import "encore.dev/pubsub"
type OrderCreatedEvent struct {
OrderID string `json:"order_id"`
UserID string `json:"user_id"`
Total int `json:"total"`
}
// Package level declaration
var OrderCreated = pubsub.NewTopic[*OrderCreatedEvent]("order-created", pubsub.TopicConfig{
DeliveryGuarantee: pubsub.AtLeastOnce,
})Publishing
发布消息
go
msgID, err := events.OrderCreated.Publish(ctx, &events.OrderCreatedEvent{
OrderID: "123",
UserID: "user-456",
Total: 9999,
})go
msgID, err := events.OrderCreated.Publish(ctx, &events.OrderCreatedEvent{
OrderID: "123",
UserID: "user-456",
Total: 9999,
})Subscriptions
订阅
go
package notifications
import (
"context"
"myapp/events"
"encore.dev/pubsub"
)
var _ = pubsub.NewSubscription(events.OrderCreated, "send-confirmation-email",
pubsub.SubscriptionConfig[*events.OrderCreatedEvent]{
Handler: sendConfirmationEmail,
},
)
func sendConfirmationEmail(ctx context.Context, event *events.OrderCreatedEvent) error {
// Send email...
return nil
}go
package notifications
import (
"context"
"myapp/events"
"encore.dev/pubsub"
)
var _ = pubsub.NewSubscription(events.OrderCreated, "send-confirmation-email",
pubsub.SubscriptionConfig[*events.OrderCreatedEvent]{
Handler: sendConfirmationEmail,
},
)
func sendConfirmationEmail(ctx context.Context, event *events.OrderCreatedEvent) error {
// 发送邮件...
return nil
}Cron Jobs
Cron 任务
go
package cleanup
import (
"context"
"encore.dev/cron"
)
// The cron job declaration
var _ = cron.NewJob("cleanup-sessions", cron.JobConfig{
Title: "Clean up expired sessions",
Schedule: "0 * * * *", // Every hour
Endpoint: CleanupExpiredSessions,
})
//encore:api private
func CleanupExpiredSessions(ctx context.Context) error {
// Cleanup logic
return nil
}go
package cleanup
import (
"context"
"encore.dev/cron"
)
// The cron job declaration
var _ = cron.NewJob("cleanup-sessions", cron.JobConfig{
Title: "Clean up expired sessions",
Schedule: "0 * * * *", // 每小时执行一次
Endpoint: CleanupExpiredSessions,
})
//encore:api private
func CleanupExpiredSessions(ctx context.Context) error {
// 清理逻辑
return nil
}Schedule Formats
调度格式
| Format | Example | Description |
|---|---|---|
| Cron expression | | 9am every Monday |
| Every interval | | Every hour |
| Every interval | | Every 30 minutes |
| 格式 | 示例 | 描述 |
|---|---|---|
| Cron表达式 | | 每周一上午9点 |
| 固定间隔 | | 每小时一次 |
| 固定间隔 | | 每30分钟一次 |
Object Storage
对象存储
go
package uploads
import "encore.dev/storage/objects"
// Package level
var Uploads = objects.NewBucket("user-uploads", objects.BucketConfig{})
// Public bucket
var PublicAssets = objects.NewBucket("public-assets", objects.BucketConfig{
Public: true,
})go
package uploads
import "encore.dev/storage/objects"
// Package level
var Uploads = objects.NewBucket("user-uploads", objects.BucketConfig{})
// 公开存储桶
var PublicAssets = objects.NewBucket("public-assets", objects.BucketConfig{
Public: true,
})Operations
操作示例
go
// Upload
attrs, err := uploads.Uploads.Upload(ctx, "path/to/file.jpg", bytes.NewReader(data),
objects.UploadOptions{
ContentType: "image/jpeg",
},
)
// Download
reader, err := uploads.Uploads.Download(ctx, "path/to/file.jpg")
defer reader.Close()
data, _ := io.ReadAll(reader)
// Check existence
attrs, err := uploads.Uploads.Attrs(ctx, "path/to/file.jpg")
// err == objects.ErrObjectNotFound if doesn't exist
// Delete
err := uploads.Uploads.Remove(ctx, "path/to/file.jpg")
// Public URL (only for public buckets)
url := uploads.PublicAssets.PublicURL("image.jpg")go
// 上传文件
attrs, err := uploads.Uploads.Upload(ctx, "path/to/file.jpg", bytes.NewReader(data),
objects.UploadOptions{
ContentType: "image/jpeg",
},
)
// 下载文件
reader, err := uploads.Uploads.Download(ctx, "path/to/file.jpg")
defer reader.Close()
data, _ := io.ReadAll(reader)
// 检查文件是否存在
attrs, err := uploads.Uploads.Attrs(ctx, "path/to/file.jpg")
// 若不存在,err == objects.ErrObjectNotFound
// 删除文件
err := uploads.Uploads.Remove(ctx, "path/to/file.jpg")
// 获取公开URL(仅适用于公开存储桶)
url := uploads.PublicAssets.PublicURL("image.jpg")Secrets
密钥管理
go
package email
import "encore.dev/config"
var secrets struct {
SendGridAPIKey config.String
SMTPPassword config.String
}
func sendEmail() error {
apiKey := secrets.SendGridAPIKey()
// Use the secret...
}Set secrets via CLI:
bash
encore secret set --type prod SendGridAPIKeygo
package email
import "encore.dev/config"
var secrets struct {
SendGridAPIKey config.String
SMTPPassword config.String
}
func sendEmail() error {
apiKey := secrets.SendGridAPIKey()
// 使用密钥...
return nil
}通过CLI设置密钥:
bash
encore secret set --type prod SendGridAPIKeyConfig Values
配置值
go
package myservice
import "encore.dev/config"
var cfg struct {
MaxRetries config.Int
BaseURL config.String
Debug config.Bool
}
func doSomething() {
if cfg.Debug() {
log.Println("Debug mode enabled")
}
}go
package myservice
import "encore.dev/config"
var cfg struct {
MaxRetries config.Int
BaseURL config.String
Debug config.Bool
}
func doSomething() {
if cfg.Debug() {
log.Println("Debug mode enabled")
}
}Guidelines
指导原则
- Infrastructure declarations MUST be at package level
- Use descriptive names for resources
- Keep migrations sequential and numbered
- Subscription handlers must be idempotent (at-least-once delivery)
- Secrets are accessed by calling them as functions
- Cron endpoints should be (internal only)
private - Each service typically has its own database
- 基础设施声明必须在包级别
- 为资源使用具有描述性的名称
- 保持迁移文件按顺序编号
- 订阅处理程序必须是幂等的(至少一次投递)
- 通过调用函数的方式访问密钥
- Cron 端点应设置为 (仅内部访问)
private - 每个服务通常拥有独立的数据库