关于 encore-go-infrastructure
用于在 Encore Go 应用中通过包级资源声明基础设施的技能,涵盖数据库、Pub/Sub、定时任务、对象存储、密钥和配置。
主要功能
- 01包级基础设施声明
- 02PostgreSQL 数据库与迁移
- 03Pub/Sub 主题与订阅
- 04定时任务调度
- 05对象存储与签名 URL
- 06密钥与配置值
适用场景
- 01声明服务数据库和迁移
- 02发布和接收事件
- 03安排定期任务
- 04管理文件存储与签名访问
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ encoredev/ skills --skill encore-go-infrastructure安装后在 Claude Code 中输入/encore-go-infrastructure确认已加载。
详细介绍
Encore Go 基础设施声明
说明
Encore Go 使用声明式基础设施——将资源定义为包级变量,Encore 会负责配置:
- 本地(
encore run)——Encore 在 Docker 中运行基础设施(Postgres、Redis 等) - 生产环境——通过 Encore Cloud 部署到你的 AWS/GCP,或使用生成的基础设施配置自行托管
重要规则
所有基础设施都必须在包级别声明,不能在函数内部声明。
数据库(PostgreSQL)
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/ 目录中创建迁移:
user/
├── user.go
├── db.go
└── migrations/
├── 1_create_users.up.sql
└── 2_add_email_index.up.sql
迁移命名格式:{number}_{description}.up.sql
Pub/Sub
主题
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,
})
发布
msgID, err := events.OrderCreated.Publish(ctx, &events.OrderCreatedEvent{
OrderID: "123",
UserID: "user-456",
Total: 9999,
})
订阅
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
}
主题引用
向库代码传递主题访问权限,同时保留静态分析能力:
// Create a reference with publish permission
ref := pubsub.TopicRef[pubsub.Publisher[*OrderCreatedEvent]](OrderCreated)
// Use the reference in library code
func publishEvent(ref pubsub.Publisher[*OrderCreatedEvent], event *OrderCreatedEvent) error {
_, err := ref.Publish(ctx, event)
return err
}
定时任务
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
}
计划格式
| 格式 | 示例 | 说明 |
|---|---|---|
| Cron 表达式 | "0 9 * * 1" | 每周一上午 9 点 |
| 固定间隔 | "every 1h" | 每小时 |
| 固定间隔 | "every 30m" | 每 30 分钟 |
对象存储
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,
})
操作
// Upload (streaming pattern)
writer := Uploads.Upload(ctx, "path/to/file.jpg")
_, err := io.Copy(writer, dataReader)
if err != nil {
writer.Abort()
return err
}
err = writer.Close()
// Download
reader := Uploads.Download(ctx, "path/to/file.jpg")
if err := reader.Err(); err != nil {
return err
}
defer reader.Close()
data, _ := io.ReadAll(reader)
// Check existence
exists, err := Uploads.Exists(ctx, "path/to/file.jpg")
// Get attributes (size, content type, ETag)
attrs, err := Uploads.Attrs(ctx, "path/to/file.jpg")
// List objects
for err, entry := range Uploads.List(ctx, &objects.Query{}) {
if err != nil {
return err
}
fmt.Println(entry.Key, entry.Size)
}
// Delete
err := Uploads.Remove(ctx, "path/to/file.jpg")
// Public URL (only for public buckets)
url := PublicAssets.PublicURL("image.jpg")
签名 URL
生成临时 URL,以便上传/下载,而无需暴露你的存储桶:
import "time"
// Signed upload URL (expires in 2 hours)
url, err := Uploads.SignedUploadURL(ctx, "user-uploads/avatar.jpg",
objects.WithTTL(time.Duration(7200)*time.Second))
// Signed download URL
url, err := Uploads.SignedDownloadURL(ctx, "documents/report.pdf",
objects.WithTTL(time.Duration(7200)*time.Second))
存储桶引用
向库代码传递具有特定权限的存储桶访问权限:
// Create a reference with download permission only
ref := objects.BucketRef[objects.Downloader](Uploads)
// Create a reference with multiple permissions
type myPerms interface {
objects.Downloader
objects.Uploader
}
ref := objects.BucketRef[myPerms](Uploads)
// Permission types: Downloader, Uploader, Lister, Attrser, Remover,
// SignedDownloader, SignedUploader, ReadWriter
密钥
package email
var secrets struct {
SendGridAPIKey string
SMTPPassword string
}
func sendEmail() error {
apiKey := secrets.SendGridAPIKey
// Use the secret...
}
通过 CLI 设置密钥:
encore secret set --type prod SendGridAPIKey
配置值
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")
}
}
指南
- 基础设施声明必须位于包级别
- 为资源使用描述性名称
- 按顺序编号并保持迁移连续
- 订阅处理程序必须具备幂等性(至少一次投递)
- 通过将密钥作为函数调用来访问
- 定时任务端点应为
private(仅限内部访问) - 每个服务通常都有自己的数据库
评论
支持 Markdown