Déployer des workers Mastra
Exécutez les workers Mastra comme processus distincts afin de dimensionner indépendamment de l’API l’orchestration, la planification et les tâches d’arrière-plan. Ce guide décrit un déploiement entièrement séparé avec Docker Compose ou Kubernetes.
Ce guide couvre la séparation des workers dans leurs propres conteneurs. Si vous avez seulement besoin que les workers s’exécutent dans le même processus que l’API, consultez Workers. Aucune configuration supplémentaire n’est nécessaire.
Avant de commencerLien direct vers Avant de commencer
Vous aurez besoin de :
- Une application Mastra
- Docker et Docker Compose, ou un cluster Kubernetes avec
kubectl - Un backend PubSub distribué : Redis pour
RedisStreamsPubSub, ou un projet Google Cloud pourGoogleCloudPubSub - Une base de données partagée accessible depuis chaque conteneur. Consultez les backends de stockage pris en charge pour la liste complète.
Le PubSub en mémoire par défaut ne peut pas transmettre des événements entre processus. Vous devez configurer un backend PubSub distribué avant de séparer les workers dans des conteneurs distincts.
Configurer l’infrastructure partagéeLien direct vers Configurer l’infrastructure partagée
Dirigez l’instance Mastra vers un backend PubSub distribué et une base de données partagée. Utilisez des variables d’environnement afin que la même image s’exécute dans chaque conteneur.
- Redis Streams + PostgreSQL
- Google Cloud Pub/Sub + LibSQL
import { Mastra } from '@mastra/core/mastra'
import { RedisStreamsPubSub } from '@mastra/redis-streams'
import { PostgresStore } from '@mastra/pg'
export const mastra = new Mastra({
storage: new PostgresStore({
connectionString: process.env.DATABASE_URL!,
}),
pubsub: new RedisStreamsPubSub({
url: process.env.REDIS_URL!,
}),
})
import { Mastra } from '@mastra/core/mastra'
import { GoogleCloudPubSub } from '@mastra/google-cloud-pubsub'
import { LibSQLStore } from '@mastra/libsql'
export const mastra = new Mastra({
storage: new LibSQLStore({
url: process.env.DATABASE_URL!,
}),
pubsub: new GoogleCloudPubSub({
projectId: process.env.GCP_PROJECT_ID!,
}),
})
Tout backend de stockage pris en charge convient. Remplacez l’adaptateur de stockage par celui de votre base de données préférée.
DéployerLien direct vers Déployer
Compilez votre application Mastra. La sortie s’exécute dans chaque conteneur.
mastra buildCette opération produit un répertoire
.mastra/output/autonome. Consultez Déployer un serveur Mastra pour les détails sur la sortie de compilation.Créez un Dockerfile qui copie la sortie précompilée et installe les dépendances de production :
app/DockerfileFROM node:22-alpineWORKDIR /appCOPY .mastra/output/package.json .mastra/output/.npmrc* ./RUN npm install --omit=devCOPY .mastra/output/ .EXPOSE 4111CMD ["node", "index.mjs"]Définissez la topologie entièrement séparée. Cette configuration exécute six services : une base de données, un backend PubSub, le serveur API et trois workers. Chaque worker exécute la même image avec une valeur
MASTRA_WORKERSdifférente pour contrôler le worker qui démarre.L’API définit
MASTRA_WORKERS: "false"pour désactiver tout traitement d’événements. Le worker d’orchestration définitMASTRA_STEP_EXECUTION_URLpour diriger les requêtes d’exécution d’étapes vers l’URL interne de l’API. Consultez l’URL d’exécution d’étapes pour plus de détails.Tous les services partagent un
MASTRA_WORKER_AUTH_TOKEN. Les workers incluent ce jeton dans leurs requêtes à l’API afin qu’elle puisse vérifier que l’appelant est un service interne de confiance. Consultez l’authentification des workers pour plus de détails.- Docker Compose
- Kubernetes
docker-compose.ymlservices:postgres:image: postgres:16-alpineenvironment:POSTGRES_USER: mastraPOSTGRES_PASSWORD: ${POSTGRES_PASSWORD}POSTGRES_DB: mastraports:- '5432:5432'volumes:- pgdata:/var/lib/postgresql/datahealthcheck:test: ['CMD-SHELL', 'pg_isready -U mastra']interval: 5stimeout: 3sretries: 5redis:image: redis:7-alpineports:- '6379:6379'healthcheck:test: ['CMD', 'redis-cli', 'ping']interval: 5stimeout: 3sretries: 5api:build: ./appports:- '4111:4111'environment:DATABASE_URL: postgres://mastra:${POSTGRES_PASSWORD}@postgres:5432/mastraREDIS_URL: redis://redis:6379MASTRA_WORKERS: 'false'MASTRA_WORKER_AUTH_TOKEN: ${MASTRA_WORKER_AUTH_TOKEN}depends_on:postgres:condition: service_healthyredis:condition: service_healthyhealthcheck:test: ['CMD', 'wget', '-qO-', 'http://localhost:4111/api/agents']interval: 5stimeout: 3sretries: 5orchestration-worker:build: ./appenvironment:DATABASE_URL: postgres://mastra:${POSTGRES_PASSWORD}@postgres:5432/mastraREDIS_URL: redis://redis:6379MASTRA_WORKERS: orchestrationMASTRA_STEP_EXECUTION_URL: http://api:4111/apiMASTRA_WORKER_AUTH_TOKEN: ${MASTRA_WORKER_AUTH_TOKEN}depends_on:api:condition: service_healthyscheduler-worker:build: ./appenvironment:DATABASE_URL: postgres://mastra:${POSTGRES_PASSWORD}@postgres:5432/mastraREDIS_URL: redis://redis:6379MASTRA_WORKERS: schedulerMASTRA_WORKER_AUTH_TOKEN: ${MASTRA_WORKER_AUTH_TOKEN}depends_on:api:condition: service_healthybackground-task-worker:build: ./appenvironment:DATABASE_URL: postgres://mastra:${POSTGRES_PASSWORD}@postgres:5432/mastraREDIS_URL: redis://redis:6379MASTRA_WORKERS: backgroundTasksMASTRA_WORKER_AUTH_TOKEN: ${MASTRA_WORKER_AUTH_TOKEN}depends_on:api:condition: service_healthyvolumes:pgdata:Créez un fichier
.envà côté de votredocker-compose.yml:.envPOSTGRES_PASSWORD=your-secure-passwordMASTRA_WORKER_AUTH_TOKEN=your-shared-secret-tokenremarqueN’oubliez pas de définir les autres variables d’environnement nécessaires à votre application, par exemple la clé API de votre fournisseur de modèles.
Créez un espace de noms et un Secret contenant vos chaînes de connexion :
k8s/namespace.yamlapiVersion: v1kind: Namespacemetadata:name: mastra-workerskubectl apply -f k8s/namespace.yamlkubectl create secret generic mastra-secrets -n mastra-workers \--from-literal=POSTGRES_PASSWORD='your-password' \--from-literal=DATABASE_URL='postgresql://mastra:your-password@postgres:5432/mastra' \--from-literal=REDIS_URL='redis://redis:6379' \--from-literal=MASTRA_WORKER_AUTH_TOKEN='your-shared-token'remarqueAjoutez les autres variables d’environnement nécessaires à votre application, par exemple la clé API de votre fournisseur de modèles, au Secret ou sous forme d’entrées
--from-literalsupplémentaires.Compilez et poussez l’image Docker vers un registre depuis lequel votre cluster peut la récupérer :
docker build -t your-registry/mastra-workers:latest ./appdocker push your-registry/mastra-workers:latestAppliquez les Deployments et Services pour la base de données, le backend PubSub, l’API et les trois workers. L’exemple ci-dessous utilise Postgres et Redis dans le cluster. En production, utilisez des services gérés, par exemple Amazon RDS, Cloud SQL, ElastiCache ou Memorystore.
k8s/postgres.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: postgresnamespace: mastra-workersspec:replicas: 1selector:matchLabels:app: postgrestemplate:metadata:labels:app: postgresspec:containers:- name: postgresimage: postgres:16-alpineports:- containerPort: 5432env:- name: POSTGRES_USERvalue: mastra- name: POSTGRES_PASSWORDvalueFrom:secretKeyRef:name: mastra-secretskey: POSTGRES_PASSWORD- name: POSTGRES_DBvalue: mastravolumeMounts:- name: pgdatamountPath: /var/lib/postgresql/datavolumes:- name: pgdataemptyDir: {}---apiVersion: v1kind: Servicemetadata:name: postgresnamespace: mastra-workersspec:selector:app: postgresports:- port: 5432targetPort: 5432attentionL’exemple Postgres ci-dessus utilise
emptyDirpour le stockage, ce qui signifie que les données sont perdues lorsque le pod redémarre. En production, remplacez-le par unPersistentVolumeClaimou utilisez un service de base de données géré.k8s/redis.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: redisnamespace: mastra-workersspec:replicas: 1selector:matchLabels:app: redistemplate:metadata:labels:app: redisspec:containers:- name: redisimage: redis:7-alpineargs: ['--appendonly', 'yes']ports:- containerPort: 6379---apiVersion: v1kind: Servicemetadata:name: redisnamespace: mastra-workersspec:selector:app: redisports:- port: 6379targetPort: 6379k8s/api.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: apinamespace: mastra-workersspec:replicas: 1selector:matchLabels:app: apitemplate:metadata:labels:app: apispec:containers:- name: apiimage: your-registry/mastra-workers:latestports:- containerPort: 4111env:- name: MASTRA_WORKERSvalue: 'false'envFrom:- secretRef:name: mastra-secretsreadinessProbe:httpGet:path: /api/agentsport: 4111initialDelaySeconds: 10periodSeconds: 5livenessProbe:httpGet:path: /api/agentsport: 4111initialDelaySeconds: 15periodSeconds: 10resources:requests:cpu: 500mmemory: 512Mi---apiVersion: v1kind: Servicemetadata:name: apinamespace: mastra-workersspec:selector:app: apiports:- port: 4111targetPort: 4111k8s/orchestration-worker.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: orchestration-workernamespace: mastra-workersspec:replicas: 1selector:matchLabels:app: orchestration-workertemplate:metadata:labels:app: orchestration-workerspec:containers:- name: workerimage: your-registry/mastra-workers:latestenv:- name: MASTRA_WORKERSvalue: orchestration- name: MASTRA_STEP_EXECUTION_URLvalue: http://api:4111/apienvFrom:- secretRef:name: mastra-secretsresources:requests:cpu: 250mmemory: 256Mik8s/scheduler-worker.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: scheduler-workernamespace: mastra-workersspec:replicas: 1selector:matchLabels:app: scheduler-workertemplate:metadata:labels:app: scheduler-workerspec:containers:- name: workerimage: your-registry/mastra-workers:latestenv:- name: MASTRA_WORKERSvalue: schedulerenvFrom:- secretRef:name: mastra-secretsresources:requests:cpu: 250mmemory: 256Mik8s/background-task-worker.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: background-task-workernamespace: mastra-workersspec:replicas: 1selector:matchLabels:app: background-task-workertemplate:metadata:labels:app: background-task-workerspec:containers:- name: workerimage: your-registry/mastra-workers:latestenv:- name: MASTRA_WORKERSvalue: backgroundTasksenvFrom:- secretRef:name: mastra-secretsresources:requests:cpu: 250mmemory: 256MiAppliquez tous les manifestes et attendez que l’API soit prête :
kubectl apply -f k8s/kubectl wait -n mastra-workers --for=condition=ready pod -l app=api --timeout=90skubectl wait -n mastra-workers --for=condition=ready pod -l app=orchestration-worker --timeout=60skubectl wait -n mastra-workers --for=condition=ready pod -l app=scheduler-worker --timeout=60skubectl wait -n mastra-workers --for=condition=ready pod -l app=background-task-worker --timeout=60sVérifiez que la pile est en cours d’exécution et que l’API répond :
- Docker Compose
- Kubernetes
docker compose up -ddocker compose pscurl http://localhost:4111/api/agentskubectl get pods -n mastra-workerskubectl port-forward -n mastra-workers svc/api 4111:4111Dans un terminal distinct :
curl http://localhost:4111/api/agentsUne liste JSON de vos Agents confirme que l’API et les workers sont en cours d’exécution.
URL d’exécution d’étapesLien direct vers URL d’exécution d’étapes
Dans un déploiement entièrement séparé, le worker d’orchestration s’exécute dans un conteneur distinct de l’API. Lorsqu’il traite un événement de Workflow, il délègue l’exécution des étapes à l’API via HTTP.
Définissez MASTRA_STEP_EXECUTION_URL sur l’URL interne de l’API, avec le préfixe /api :
MASTRA_STEP_EXECUTION_URL=http://api:4111/api
Le worker d’orchestration envoie une requête POST à ${MASTRA_STEP_EXECUTION_URL}/workflows/:workflowId/runs/:runId/steps/execute pour chaque étape. L’API résout le Workflow et exécute l’étape localement.
Sans cette variable, le worker d’orchestration tente d’exécuter les étapes dans le processus. Cela fonctionne lorsque le worker s’exécute avec l’API, mais échoue dans les déploiements séparés, où il n’a pas accès au runtime Mastra complet.
Mise à l’échelleLien direct vers Mise à l’échelle
Les workers d’orchestration et de tâches d’arrière-plan peuvent être mis à l’échelle horizontalement en toute sécurité. Les groupes de consommateurs PubSub distribuent les événements entre les instances : chaque événement n’est donc traité qu’une fois.
- Docker Compose
- Kubernetes
docker compose up -d --scale orchestration-worker=3
docker compose up -d --scale background-task-worker=2
kubectl scale deployment/orchestration-worker -n mastra-workers --replicas=3
kubectl scale deployment/background-task-worker -n mastra-workers --replicas=2
Pour la mise à l’échelle automatique, ajoutez un HorizontalPodAutoscaler :
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: orchestration-worker
namespace: mastra-workers
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: orchestration-worker
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
La mise à l’échelle automatique fondée sur le processeur nécessite que metrics-server s’exécute dans le cluster. Les clusters gérés tels que GKE, EKS et AKS l’incluent par défaut.
L’API peut également être mise à l’échelle horizontalement derrière un équilibreur de charge.
Ne mettez pas à l’échelle le worker planificateur. Exécutez exactement une instance. Plusieurs planificateurs qui interrogent le même stockage déclenchent des événements dupliqués pour une même planification.
Récupération après incidentLien direct vers Récupération après incident
Les workers se remettent d’un incident, car le backend PubSub distribué conserve les événements non acquittés :
- Worker d’orchestration : les événements en attente restent dans le backend PubSub. Au redémarrage, le worker reprend là où il s’était arrêté.
- Worker planificateur : aucun événement n’est manqué de façon permanente. Au redémarrage, le planificateur calcule l’heure du prochain déclenchement à partir de l’heure actuelle, et non de l’endroit où il s’était arrêté.
- API durant l’exécution d’une étape : la requête HTTP du worker d’orchestration échoue. L’événement est rejeté puis renvoyé à la tentative suivante.
Si l’API se bloque alors qu’une étape est déjà en cours d’exécution, par exemple au milieu d’une veille, le travail de cette étape est perdu. L’exécution de Workflow peut rester bloquée dans l’état running. Mastra ne dispose pas encore d’une récupération automatique fondée sur un délai d’attente pour ce scénario.
À consulter égalementLien direct vers À consulter également
- Workers : ce que sont les workers et quand les utiliser
- Authentification des workers : communication sécurisée entre worker et API
- Référence des workers : détails de configuration pour tous les types de workers
- Référence de la CLI :
mastra worker buildetmastra worker start - PubSub : backends de transmission des événements
- Déployer un serveur Mastra : sortie de compilation et configuration du serveur
- Déployer Mastra sur Kubernetes : déploiement multi-pods avec Agents durables