encore-go-infrastructure について
Encore Go アプリケーションでパッケージレベルのリソースを使ってインフラを宣言するスキルです。データベース、Pub/Sub、Cron、オブジェクトストレージ、シークレット、設定を扱います。
主な機能
- 01パッケージレベルのインフラ宣言
- 02PostgreSQL データベースとマイグレーション
- 03Pub/Sub トピックとサブスクリプション
- 04Cron ジョブのスケジュール
- 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
}
Cron ジョブ
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" | 1時間ごと |
| インターバル | "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")
}
}
ガイドライン
- インフラストラクチャの宣言はパッケージレベルで行う必要があります
- リソースには説明的な名前を使用してください
- マイグレーションは連番で順序を保ってください
- サブスクリプションハンドラーは冪等でなければなりません (少なくとも1回の配信)
- シークレットは関数として呼び出すことでアクセスします
- Cron エンドポイントは
private(内部のみ) にする必要があります - 通常、各サービスは独自のデータベースを持ちます
コメント
Markdown 対応