Déclaration d'Infrastructure Encore Go
Instructions
Encore Go utilise une infrastructure déclarative - vous définissez des ressources comme des variables au niveau du package et Encore gère le provisioning :
- Localement (
encore run) - Encore exécute l'infrastructure dans Docker (Postgres, Redis, etc.) - Production - Déployez via Encore Cloud sur votre AWS/GCP, ou auto-hébergez en utilisant la configuration d'infrastructure générée
Règle Critique
Toute infrastructure doit être déclarée au niveau du package, jamais à l'intérieur de fonctions.
Bases de Données (PostgreSQL)
package user
import "encore.dev/storage/sqldb"
// CORRECT : Niveau du package
var db = sqldb.NewDatabase("userdb", sqldb.DatabaseConfig{
Migrations: "./migrations",
})
// FAUX : À l'intérieur d'une fonction
func setup() {
db := sqldb.NewDatabase("userdb", sqldb.DatabaseConfig{...})
}
Migrations
Créez les migrations dans le répertoire migrations/ :
user/
├── user.go
├── db.go
└── migrations/
├── 1_create_users.up.sql
└── 2_add_email_index.up.sql
Nommage des migrations : {number}_{description}.up.sql
Pub/Sub
Topics
package events
import "encore.dev/pubsub"
type OrderCreatedEvent struct {
OrderID string `json:"order_id"`
UserID string `json:"user_id"`
Total int `json:"total"`
}
// Déclaration au niveau du package
var OrderCreated = pubsub.NewTopic[*OrderCreatedEvent]("order-created", pubsub.TopicConfig{
DeliveryGuarantee: pubsub.AtLeastOnce,
})
Publication
msgID, err := events.OrderCreated.Publish(ctx, &events.OrderCreatedEvent{
OrderID: "123",
UserID: "user-456",
Total: 9999,
})
Souscriptions
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 {
// Envoyer l'email...
return nil
}
Références de Topics
Transmettez l'accès au topic au code de bibliothèque tout en maintenant l'analyse statique :
// Créer une référence avec permission de publication
ref := pubsub.TopicRef[pubsub.Publisher[*OrderCreatedEvent]](OrderCreated)
// Utiliser la référence dans le code de bibliothèque
func publishEvent(ref pubsub.Publisher[*OrderCreatedEvent], event *OrderCreatedEvent) error {
_, err := ref.Publish(ctx, event)
return err
}
Tâches Cron
package cleanup
import (
"context"
"encore.dev/cron"
)
// La déclaration de la tâche cron
var _ = cron.NewJob("cleanup-sessions", cron.JobConfig{
Title: "Clean up expired sessions",
Schedule: "0 * * * *", // Toutes les heures
Endpoint: CleanupExpiredSessions,
})
//encore:api private
func CleanupExpiredSessions(ctx context.Context) error {
// Logique de nettoyage
return nil
}
Formats de Planification
| Format | Exemple | Description |
|---|---|---|
| Expression cron | "0 9 * * 1" |
9h tous les lundis |
| Intervalle | "every 1h" |
Toutes les heures |
| Intervalle | "every 30m" |
Tous les 30 minutes |
Stockage d'Objets
package uploads
import "encore.dev/storage/objects"
// Niveau du package
var Uploads = objects.NewBucket("user-uploads", objects.BucketConfig{})
// Bucket public
var PublicAssets = objects.NewBucket("public-assets", objects.BucketConfig{
Public: true,
})
Opérations
// Téléverser (pattern streaming)
writer := Uploads.Upload(ctx, "path/to/file.jpg")
_, err := io.Copy(writer, dataReader)
if err != nil {
writer.Abort()
return err
}
err = writer.Close()
// Télécharger
reader := Uploads.Download(ctx, "path/to/file.jpg")
if err := reader.Err(); err != nil {
return err
}
defer reader.Close()
data, _ := io.ReadAll(reader)
// Vérifier l'existence
exists, err := Uploads.Exists(ctx, "path/to/file.jpg")
// Obtenir les attributs (taille, type de contenu, ETag)
attrs, err := Uploads.Attrs(ctx, "path/to/file.jpg")
// Lister les objets
for err, entry := range Uploads.List(ctx, &objects.Query{}) {
if err != nil {
return err
}
fmt.Println(entry.Key, entry.Size)
}
// Supprimer
err := Uploads.Remove(ctx, "path/to/file.jpg")
// URL publique (uniquement pour les buckets publics)
url := PublicAssets.PublicURL("image.jpg")
URLs Signées
Générez des URLs temporaires pour téléverser/télécharger sans exposer votre bucket :
import "time"
// URL de téléversement signée (expire dans 2 heures)
url, err := Uploads.SignedUploadURL(ctx, "user-uploads/avatar.jpg",
objects.WithTTL(time.Duration(7200)*time.Second))
// URL de téléchargement signée
url, err := Uploads.SignedDownloadURL(ctx, "documents/report.pdf",
objects.WithTTL(time.Duration(7200)*time.Second))
Références de Buckets
Transmettez l'accès au bucket avec des permissions spécifiques au code de bibliothèque :
// Créer une référence avec permission de téléchargement uniquement
ref := objects.BucketRef[objects.Downloader](Uploads)
// Créer une référence avec plusieurs permissions
type myPerms interface {
objects.Downloader
objects.Uploader
}
ref := objects.BucketRef[myPerms](Uploads)
// Types de permissions : Downloader, Uploader, Lister, Attrser, Remover,
// SignedDownloader, SignedUploader, ReadWriter
Secrets
package email
var secrets struct {
SendGridAPIKey string
SMTPPassword string
}
func sendEmail() error {
apiKey := secrets.SendGridAPIKey
// Utiliser le secret...
}
Définissez les secrets via CLI :
encore secret set --type prod SendGridAPIKey
Valeurs de Configuration
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")
}
}
Recommandations
- Les déclarations d'infrastructure DOIVENT être au niveau du package
- Utilisez des noms descriptifs pour les ressources
- Gardez les migrations séquentielles et numérotées
- Les handlers de souscription doivent être idempotents (livraison au moins une fois)
- Les secrets sont accédés en les appelant comme des fonctions
- Les endpoints cron doivent être
private(internes uniquement) - Chaque service a généralement sa propre base de données