Saltar a contenido

Guia de Programacion

Otros idiomas

La guia de ejecucion gobernada describe el comportamiento del runtime en esta rama: el registro almacena la configuracion sin ejecutar un agente; las invocaciones por API, manuales y por temporizador reciben IDs de ejecucion distintos y resultados terminales reales. El historial alcanza succeeded despues de la ejecucion y la limpieza, e incluye la salida, los errores y las referencias de auditoria protegida. La programacion de CLI administrada, los modelos enrutados y el transporte de agentes externos siguen sin estar disponibles en el servicio predeterminado. El limite de comandos seleccionado puede usar Firecracker para herramientas oneshot, parsers, MCP stdio y sesiones PTY cuando se aprovisionan los artefactos de invitado correspondientes. Consulte la guia de la rama para conocer las diferencias visibles para el operador y la cobertura pendiente.

El sistema de programacion de Symbiont proporciona ejecucion de tareas basada en cron de nivel de produccion para agentes de IA. El sistema soporta:

  • Programaciones cron: Sintaxis cron tradicional para tareas recurrentes
  • Trabajos de una sola ejecucion: Ejecutar una vez en un momento especifico
  • Patron de latido (heartbeat): Ciclos continuos de evaluacion-accion-pausa para agentes de monitoreo
  • Aislamiento de sesion: Contextos de agente efimeros, compartidos o completamente aislados
  • Enrutamiento de entrega: Multiples canales de salida (Stdout, LogFile, Webhook, Slack, Email, Custom)
  • Aplicacion de politicas: Verificaciones de seguridad y cumplimiento antes de la ejecucion
  • Robustez para produccion: Jitter, limites de concurrencia, colas de mensajes no entregados y verificacion de AgentPin

Arquitectura

El sistema de programacion esta construido sobre tres componentes principales:

┌─────────────────────┐
│   CronScheduler     │  Bucle de ticks en segundo plano (intervalos de 1 segundo)
│   (Tick Loop)       │  Seleccion de trabajos y orquestacion de ejecucion
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│   SqliteJobStore    │  Almacenamiento persistente de trabajos
│   (Job Storage)     │  Soporte de transacciones, gestion de estado
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│DefaultAgentScheduler│  Entorno de ejecucion de agentes
│ (Execution Engine)  │  Gestion del ciclo de vida de AgentContext
└─────────────────────┘

CronScheduler

El CronScheduler es el punto de entrada principal. Gestiona:

  • Bucle de ticks en segundo plano ejecutandose a intervalos de 1 segundo
  • Seleccion de trabajos basada en el siguiente tiempo de ejecucion
  • Control de concurrencia e inyeccion de jitter
  • Recoleccion de metricas y monitoreo de salud
  • Apagado gracioso con seguimiento de trabajos en curso

SqliteJobStore

El SqliteJobStore proporciona persistencia durable de trabajos con:

  • Transacciones ACID para actualizaciones de estado de trabajos
  • Seguimiento del ciclo de vida de trabajos (Active, Paused, Completed, Failed, DeadLetter)
  • Historial de ejecuciones con pista de auditoria
  • Capacidades de consulta para filtrar por estado, ID de agente, etc.

DefaultAgentScheduler

El DefaultAgentScheduler ejecuta los agentes programados:

  • Crea instancias de AgentContext aisladas o compartidas
  • Gestiona el ciclo de vida de la sesion (crear, ejecutar, destruir)
  • Enruta la entrega a los canales configurados
  • Aplica puertas de politica antes de la ejecucion

Sintaxis DSL

Estructura del Bloque de Programacion

Los bloques de programacion se definen en archivos DSL de Symbiont:

schedule {
  name: "daily-report"
  agent: "reporter-agent"
  cron: "0 0 9 * * *"

  session_mode: "ephemeral_with_summary"
  delivery: ["stdout", "log_file"]

  policy {
    require_approval: false
    max_runtime: "5m"
  }
}

Sintaxis Cron

Sintaxis cron extendida con seis campos (segundos primero, campo opcional septimo para ano):

┌─────────────── segundo (0-59)
│ ┌───────────── minuto (0-59)
│ │ ┌─────────── hora (0-23)
│ │ │ ┌───────── dia del mes (1-31)
│ │ │ │ ┌─────── mes (1-12)
│ │ │ │ │ ┌───── dia de la semana (0-6, Domingo = 0)
│ │ │ │ │ │
* * * * * *

Ejemplos:

# Todos los dias a las 9 AM
cron: "0 0 9 * * *"

# Cada lunes a las 6 PM
cron: "0 0 18 * * 1"

# Cada 15 minutos
cron: "0 */15 * * * *"

# Primer dia de cada mes a medianoche
cron: "0 0 0 1 * *"

Trabajos de Una Sola Ejecucion (Sintaxis At)

Para trabajos que se ejecutan una sola vez en un momento especifico:

schedule {
  name: "deployment-check"
  agent: "health-checker"
  at: "2026-02-15T14:30:00Z"  # Marca de tiempo ISO 8601

  delivery: ["webhook"]
  webhook_url: "https://ops.example.com/hooks/deployment"
}

Patron de Latido (Heartbeat)

Para agentes de monitoreo continuo que evaluan -> actuan -> duermen:

schedule {
  name: "system-monitor"
  agent: "heartbeat-agent"
  cron: "0 */5 * * * *"  # Despertar cada 5 minutos

  heartbeat: {
    enabled: true
    context_mode: "ephemeral_with_summary"
    max_iterations: 100  # Limite de seguridad
  }
}

El agente de latido sigue este ciclo:

  1. Evaluacion: Evaluar el estado del sistema (por ejemplo, verificar metricas, registros)
  2. Accion: Tomar accion correctiva si es necesario (por ejemplo, reiniciar servicio, alertar a operaciones)
  3. Pausa: Esperar hasta el siguiente tick programado

Comandos CLI

symbi cron gestiona el ciclo de vida de los trabajos programados. Cada subcomando que figura a continuacion se muestra con las opciones que realmente acepta; ejecute symbi cron <subcomando> --help para confirmarlo contra su compilacion.

Listar Trabajos

symbi cron list

list no acepta opciones. Use symbi cron status <job-id> para ver el detalle de un trabajo, o symbi cron history para filtrar los registros de ejecucion.

Agregar Trabajo

--name, --cron y --agent son obligatorios. El agente ya debe estar registrado; add no lee un archivo DSL.

symbi cron add --name "daily-report" --cron "0 0 9 * * * *" --agent reporter

# Fijar una zona horaria (UTC por defecto) y una politica, y desactivar tras una ejecucion
symbi cron add --name "one-off" --cron "0 */5 * * * * *" --agent reporter \
  --tz "America/New_York" --policy strict --one-shot
Opcion Requerido Significado
--name <NAME> Si Nombre del trabajo
--cron <EXPR> Si Expresion cron, siete campos (segundos primero)
--agent <AGENT> Si Nombre del agente registrado que debe ejecutarse
--tz <TIMEZONE> No Zona horaria IANA, UTC por defecto
--policy <POLICY> No Politica a aplicar a la ejecucion
--one-shot No Ejecutar una vez y luego desactivar el trabajo

Eliminar, Pausar, Reanudar

Cada uno toma un unico UUID de trabajo y ninguna opcion.

symbi cron remove <job-id>
symbi cron pause <job-id>    # detiene la programacion, preserva el estado
symbi cron resume <job-id>   # las ocurrencias sin resolver bloquean la reanudacion

Estado

symbi cron status <job-id>

status toma un UUID de trabajo y ninguna opcion. Informa el detalle del trabajo y sus ejecuciones recientes, incluido un estado Reconciled con el error original y la resolucion del operador cuando una invocacion fue reconciliada.

Ejecutar Ahora

symbi cron run <job-id>

Activa el trabajo de inmediato de forma forzada. Un disparo manual requiere un token administrativo y un UUID Idempotency-Key en la superficie REST; reutilice el mismo UUID para reintentar, no para ejecutar dos veces. Consulte estados de reintento del programador y recuperacion de cron.

Historial

# Ejecuciones recientes de todos los trabajos (20 por defecto)
symbi cron history

# Un solo trabajo, con un limite explicito de registros
symbi cron history --job <job-id> --limit 50
Opcion Significado
--job <JOB_ID> Filtrar a un solo trabajo
--limit <N> Maximo de registros a mostrar, 20 por defecto

Patron de Latido (Heartbeat)

HeartbeatContextMode

Controla como persiste el contexto entre iteraciones del heartbeat:

pub enum HeartbeatContextMode {
    /// Fresh context each iteration, append summary to run history
    EphemeralWithSummary,

    /// Shared context across all iterations (memory accumulates)
    SharedPersistent,

    /// Fresh context each iteration, no summary (stateless)
    FullyEphemeral,
}

EphemeralWithSummary (predeterminado): - Nuevo AgentContext por iteracion - Resumen de la iteracion anterior adjunto al contexto - Previene el crecimiento ilimitado de memoria - Mantiene continuidad para acciones relacionadas

SharedPersistent: - Un solo AgentContext reutilizado en todas las iteraciones - Historial completo de conversacion preservado - Mayor uso de memoria - Ideal para agentes que necesitan contexto profundo (por ejemplo, sesiones de depuracion)

FullyEphemeral: - Nuevo AgentContext por iteracion, sin traspaso - Menor huella de memoria - Ideal para verificaciones independientes (por ejemplo, sondas de salud de API)

Ejemplo de Agente Heartbeat

agent heartbeat_monitor {
  model: "claude-sonnet-4.5"
  system_prompt: """
  You are a system monitoring agent. On each heartbeat:
  1. Check system metrics (CPU, memory, disk)
  2. Review recent error logs
  3. If issues detected, take action:
     - Restart services if safe
     - Alert ops team via Slack
     - Log incident details
  4. Summarize findings
  5. Return 'sleep' when done
  """
}

schedule {
  name: "heartbeat-monitor"
  agent: "heartbeat_monitor"
  cron: "0 */10 * * * *"  # Cada 10 minutos

  heartbeat: {
    enabled: true
    context_mode: "ephemeral_with_summary"
    max_iterations: 50
  }

  delivery: ["log_file", "slack"]
  slack_channel: "#ops-alerts"
}

Aislamiento de Sesion

Modos de Sesion

pub enum HeartbeatContextMode {
    /// Ephemeral context with summary carryover (default)
    EphemeralWithSummary,

    /// Shared persistent context across all runs
    SharedPersistent,

    /// Fully ephemeral, no state carryover
    FullyEphemeral,
}

Configuracion:

schedule {
  name: "data-pipeline"
  agent: "etl-agent"
  cron: "0 0 2 * * *"

  # Contexto nuevo por ejecucion, resumen de la ejecucion anterior incluido
  session_mode: "ephemeral_with_summary"
}

Ciclo de Vida de la Sesion

Para cada ejecucion programada:

  1. Pre-ejecucion: Verificar limites de concurrencia, aplicar jitter
  2. Creacion de sesion: Crear AgentContext basado en session_mode
  3. Puerta de politica: Evaluar condiciones de politica
  4. Ejecucion: Ejecutar agente con entrada y contexto
  5. Entrega: Enrutar salida a los canales configurados
  6. Limpieza de sesion: Destruir o persistir contexto segun el modo
  7. Post-ejecucion: Actualizar registro de ejecucion, recolectar metricas

Enrutamiento de Entrega

Canales Soportados

pub enum DeliveryChannel {
    Stdout,           // Print to console
    LogFile,          // Append to job-specific log file
    Webhook,          // HTTP POST to URL
    Slack,            // Slack webhook or API
    Email,            // SMTP email
    Custom(String),   // User-defined channel
}

Ejemplos de Configuracion

Canal unico:

schedule {
  name: "backup"
  agent: "backup-agent"
  cron: "0 0 3 * * *"
  delivery: ["log_file"]
}

Multiples canales:

schedule {
  name: "security-scan"
  agent: "scanner"
  cron: "0 0 1 * * *"

  delivery: ["log_file", "slack", "email"]

  slack_channel: "#security"
  email_recipients: ["ops@example.com", "security@example.com"]
}

Entrega por webhook:

schedule {
  name: "metrics-report"
  agent: "metrics-agent"
  cron: "0 */30 * * * *"

  delivery: ["webhook"]
  webhook_url: "https://metrics.example.com/ingest"
  webhook_headers: {
    "Authorization": "Bearer ${METRICS_API_KEY}"
    "Content-Type": "application/json"
  }
}

Trait DeliveryRouter

Los canales de entrega personalizados implementan:

#[async_trait]
pub trait DeliveryRouter: Send + Sync {
    async fn route(
        &self,
        channel: &DeliveryChannel,
        job: &CronJobDefinition,
        run: &JobRunRecord,
        output: &str,
    ) -> Result<(), SchedulerError>;
}

Aplicacion de Politicas

PolicyGate

El PolicyGate evalua politicas especificas de programacion antes de la ejecucion:

pub struct PolicyGate {
    policy_engine: Arc<RealPolicyParser>,
}

impl PolicyGate {
    pub fn evaluate(
        &self,
        job: &CronJobDefinition,
        context: &AgentContext,
    ) -> Result<SchedulePolicyDecision, SchedulerError>;
}

Condiciones de Politica

schedule {
  name: "production-deploy"
  agent: "deploy-agent"
  cron: "0 0 0 * * 0"  # Domingo a medianoche

  policy {
    # Requerir aprobacion humana antes de la ejecucion
    require_approval: true

    # Tiempo maximo de ejecucion antes de terminacion forzada
    max_runtime: "30m"

    # Requerir capacidades especificas
    require_capabilities: ["deployment", "production_write"]

    # Aplicacion de ventana de tiempo (UTC)
    allowed_hours: {
      start: "00:00"
      end: "04:00"
    }

    # Restricciones de entorno
    allowed_environments: ["staging", "production"]

    # Verificacion de AgentPin requerida
    require_agent_pin: true
  }
}

SchedulePolicyDecision

pub enum SchedulePolicyDecision {
    Allow,
    Deny { reason: String },
    RequiresApproval { approver: String, reason: String, policy_id: String },
}

Robustez para Produccion

Jitter

Previene la estampida (thundering herd) cuando multiples trabajos comparten una programacion:

pub struct CronSchedulerConfig {
    pub max_jitter_seconds: u64,  // Random delay 0-N seconds
    // ...
}

Ejemplo:

[scheduler]
max_jitter_seconds = 30  # Distribuir inicios de trabajos en una ventana de 30 segundos

Concurrencia por Trabajo

Limitar ejecuciones concurrentes por trabajo para prevenir el agotamiento de recursos:

schedule {
  name: "data-sync"
  agent: "sync-agent"
  cron: "0 */5 * * * *"

  max_concurrent: 2  # Permitir maximo 2 ejecuciones concurrentes
}

Si un trabajo ya se esta ejecutando al maximo de concurrencia, el programador omite el tick.

Cola de Mensajes No Entregados (Dead-Letter Queue)

Los trabajos que exceden max_retries pasan al estado DeadLetter para revision manual:

schedule {
  name: "flaky-job"
  agent: "unreliable-agent"
  cron: "0 0 * * * *"

  max_retries: 3  # Despues de 3 fallos, mover a dead-letter
}

Recuperacion:

# Listar los trabajos y encontrar el que esta desactivado
symbi cron list

# Revisar sus registros de ejecucion, incluidos los fallos
symbi cron history --job <job-id>

# Reactivar despues de corregir la causa
symbi cron resume <job-id>

cron list y cron history no filtran por estado; lea la columna de estado de list, o los registros de ejecucion de history. No existe un subcomando cron reset -- resume reactiva un trabajo, y una ocurrencia sin resolver bloquea la reanudacion hasta que un operador la reconcilia.

Verificacion de AgentPin

Verificar criptograficamente la identidad del agente antes de la ejecucion:

schedule {
  name: "secure-task"
  agent: "trusted-agent"
  cron: "0 0 * * * *"

  agent_pin_jwt: "${AGENT_PIN_JWT}"  # JWT ES256 de agentpin-cli

  policy {
    require_agent_pin: true
  }
}

El programador verifica: 1. Firma JWT usando ES256 (ECDSA P-256) 2. El ID del agente coincide con el claim iss 3. El ancla de dominio coincide con el origen esperado 4. La expiracion (exp) es valida

Los fallos activan el evento de auditoria SecurityEventType::AgentPinVerificationFailed.

Endpoints de la API HTTP

Gestion de Programacion

POST /api/v1/schedule Crear un nuevo trabajo programado.

curl -X POST http://localhost:8080/api/v1/schedule \
  -H "Content-Type: application/json" \
  -d '{
    "name": "hourly-report",
    "agent_id": "reporter",
    "cron_expr": "0 0 * * * *",
    "session_mode": "ephemeral_with_summary",
    "delivery": ["stdout"]
  }'

GET /api/v1/schedule Listar todos los trabajos (filtrable por estado, ID de agente).

curl "http://localhost:8080/api/v1/schedule?status=active&agent_id=reporter"

GET /api/v1/schedule/{job_id} Obtener detalles del trabajo.

curl http://localhost:8080/api/v1/schedule/job-123

PUT /api/v1/schedule/{job_id} Actualizar trabajo (expresion cron, entrega, etc.).

curl -X PUT http://localhost:8080/api/v1/schedule/job-123 \
  -H "Content-Type: application/json" \
  -d '{"cron_expr": "0 0 */2 * * *"}'

DELETE /api/v1/schedule/{job_id} Eliminar trabajo.

curl -X DELETE http://localhost:8080/api/v1/schedule/job-123

POST /api/v1/schedule/{job_id}/pause Pausar trabajo.

curl -X POST http://localhost:8080/api/v1/schedule/job-123/pause

POST /api/v1/schedule/{job_id}/resume Reanudar trabajo pausado.

curl -X POST http://localhost:8080/api/v1/schedule/job-123/resume

POST /api/v1/schedule/{job_id}/run Activar ejecucion inmediata.

curl -X POST http://localhost:8080/api/v1/schedule/job-123/run \
  -H "Content-Type: application/json" \
  -d '{"input": "Run with custom input"}'

GET /api/v1/schedule/{job_id}/history Obtener historial de ejecuciones.

curl "http://localhost:8080/api/v1/schedule/job-123/history?limit=20&status=failed"

GET /api/v1/schedule/{job_id}/next_run Obtener el proximo tiempo de ejecucion programado.

curl http://localhost:8080/api/v1/schedule/job-123/next_run

Monitoreo de Salud

GET /api/v1/health/scheduler Salud y metricas del programador.

curl http://localhost:8080/api/v1/health/scheduler

Respuesta:

{
  "status": "healthy",
  "active_jobs": 15,
  "paused_jobs": 3,
  "in_flight_jobs": 2,
  "metrics": {
    "runs_total": 1234,
    "runs_succeeded": 1180,
    "runs_failed": 54,
    "avg_execution_time_ms": 850
  }
}

Ejemplos del SDK

SDK de JavaScript

import { SymbiontClient } from '@symbiont/sdk-js';

const client = new SymbiontClient({
  baseUrl: 'http://localhost:8080',
  apiKey: process.env.SYMBI_API_KEY
});

// Crear trabajo programado
const job = await client.schedule.create({
  name: 'daily-backup',
  agentId: 'backup-agent',
  cronExpr: '0 0 2 * * *',
  sessionMode: 'ephemeral_with_summary',
  delivery: ['webhook'],
  webhookUrl: 'https://backup.example.com/notify'
});

console.log(`Created job: ${job.id}`);

// Listar trabajos activos
const activeJobs = await client.schedule.list({ status: 'active' });
console.log(`Active jobs: ${activeJobs.length}`);

// Obtener estado del trabajo
const status = await client.schedule.getStatus(job.id);
console.log(`Next run: ${status.next_run}`);

// Activar ejecucion inmediata
await client.schedule.runNow(job.id, { input: 'Backup database' });

// Pausar trabajo
await client.schedule.pause(job.id);

// Ver historial
const history = await client.schedule.getHistory(job.id, { limit: 10 });
history.forEach(run => {
  console.log(`Run ${run.id}: ${run.status} (${run.execution_time_ms}ms)`);
});

// Reanudar trabajo
await client.schedule.resume(job.id);

// Eliminar trabajo
await client.schedule.delete(job.id);

SDK de Python

from symbiont import SymbiontClient

client = SymbiontClient(
    base_url='http://localhost:8080',
    api_key=os.environ['SYMBI_API_KEY']
)

# Crear trabajo programado
job = client.schedule.create(
    name='hourly-metrics',
    agent_id='metrics-agent',
    cron_expr='0 0 * * * *',
    session_mode='ephemeral_with_summary',
    delivery=['slack', 'log_file'],
    slack_channel='#metrics'
)

print(f"Created job: {job.id}")

# Listar trabajos para un agente especifico
jobs = client.schedule.list(agent_id='metrics-agent')
print(f"Found {len(jobs)} jobs for metrics-agent")

# Obtener detalles del trabajo
details = client.schedule.get(job.id)
print(f"Cron: {details.cron_expr}")
print(f"Next run: {details.next_run}")

# Actualizar expresion cron
client.schedule.update(job.id, cron_expr='0 */30 * * * *')

# Activar ejecucion inmediata
run = client.schedule.run_now(job.id, input='Generate metrics report')
print(f"Run ID: {run.id}")

# Pausar durante mantenimiento
client.schedule.pause(job.id)
print("Job paused for maintenance")

# Ver fallos recientes
history = client.schedule.get_history(
    job.id,
    status='failed',
    limit=5
)
for run in history:
    print(f"Failed run {run.id}: {run.error_message}")

# Reanudar despues del mantenimiento
client.schedule.resume(job.id)

# Verificar salud del programador
health = client.schedule.health()
print(f"Scheduler status: {health.status}")
print(f"Active jobs: {health.active_jobs}")
print(f"In-flight jobs: {health.in_flight_jobs}")

Configuracion

CronSchedulerConfig

pub struct CronSchedulerConfig {
    /// Tick interval (default: 1 second)
    pub tick_interval: Duration,

    /// Global concurrency limit (default: 100)
    pub max_concurrent_cron_jobs: usize,

    /// Persistent job store path (default: None)
    pub job_store_path: Option<PathBuf>,

    /// Catch up missed runs on startup (default: true)
    pub enable_missed_run_catchup: bool,
}

Configuracion TOML

[scheduler]
tick_interval_seconds = 1
max_jitter_seconds = 30
max_concurrent_jobs = 20
enable_metrics = true
default_max_retries = 3
shutdown_timeout_seconds = 60

Canales de entrega

Los canales de entrega (stdout, log_file, webhook, slack, email, ...) se configuran por programacion en el bloque delivery de esa programacion (ver los ejemplos anteriores), no mediante una seccion de configuracion global [scheduler.delivery].

La entrega log_file requiere SYMBIONT_LOG_DIR. La ruta de destino esta confinada a ese directorio en lista blanca — las rutas que escapan de el mediante .., rutas absolutas o symlinks son rechazadas, y la entrega de archivos de log es fail-closed (deshabilitada) cuando SYMBIONT_LOG_DIR no esta definido.

Observabilidad

Metricas (compatibles con Prometheus)

# Ejecuciones totales
symbiont_cron_runs_total{job_name="daily-report",status="succeeded"} 450

# Ejecuciones fallidas
symbiont_cron_runs_total{job_name="daily-report",status="failed"} 5

# Histograma de tiempo de ejecucion
symbiont_cron_execution_duration_seconds{job_name="daily-report"} 1.234

# Indicador de trabajos en curso
symbiont_cron_in_flight_jobs 3

# Trabajos en dead-letter
symbiont_cron_dead_letter_total{job_name="flaky-job"} 2

Eventos de Auditoria

Todas las acciones del programador emiten eventos de seguridad:

pub enum SecurityEventType {
    CronJobCreated,
    CronJobUpdated,
    CronJobDeleted,
    CronJobPaused,
    CronJobResumed,
    CronJobExecuted,
    CronJobFailed,
    CronJobDeadLettered,
    AgentPinVerificationFailed,
}

Consultar el registro de auditoria desde la shell interactiva:

/audit CronJobFailed

O programaticamente a traves de la API HTTP del runtime — consulta Referencia de la API para los endpoints /api/v1/audit.

Mejores Practicas

  1. Usar jitter para programaciones compartidas: Prevenir que multiples trabajos inicien simultaneamente
  2. Establecer limites de concurrencia: Proteger contra el agotamiento de recursos
  3. Monitorear la cola de dead-letter: Revisar y corregir trabajos fallidos regularmente
  4. Usar EphemeralWithSummary: Previene el crecimiento ilimitado de memoria en heartbeats de larga duracion
  5. Habilitar verificacion de AgentPin: Verificar criptograficamente la identidad del agente
  6. Configurar enrutamiento de entrega: Usar canales apropiados para diferentes tipos de trabajos
  7. Establecer puertas de politica: Aplicar ventanas de tiempo, aprobaciones y verificaciones de capacidades
  8. Usar patron de heartbeat para monitoreo: Ciclos continuos de evaluacion-accion-pausa
  9. Probar programaciones en staging: Validar expresiones cron y logica de trabajos antes de produccion
  10. Exportar metricas: Integrar con Prometheus/Grafana para visibilidad operativa

Solucion de Problemas

El Trabajo No Se Ejecuta

  1. Verificar el estado del trabajo: symbi cron status <job-id>
  2. Verificar la expresion cron: Usar crontab.guru
  3. Verificar la salud del programador: curl http://localhost:8080/api/v1/health/scheduler
  4. Revisar los registros: symbi logs --lines 200 (agregue --follow para seguir en vivo)

El Trabajo Falla Repetidamente

  1. Ver historial: symbi cron history --job <job-id>
  2. Verificar mensajes de error en los registros de ejecucion
  3. Verificar la configuracion y capacidades del agente
  4. Probar el agente fuera del programador: symbi run <agent-id> --input "test"
  5. Verificar puertas de politica: Asegurar que las ventanas de tiempo y capacidades coincidan

Trabajo en Dead-Letter

  1. Listar los trabajos y encontrar el que esta desactivado: symbi cron list
  2. Revisar el patron de fallos: symbi cron history --job <job-id>
  3. Corregir la causa raiz (codigo del agente, permisos, dependencias externas)
  4. Reactivar el trabajo: symbi cron resume <job-id>

Alto Uso de Memoria

  1. Verificar el modo de sesion: Cambiar a ephemeral_with_summary o fully_ephemeral
  2. Reducir iteraciones de heartbeat: Disminuir max_iterations
  3. Monitorear el tamano del contexto: Revisar la verbosidad de salida del agente
  4. Habilitar archivado de contexto: Configurar politicas de retencion

Migracion desde v0.9.0

La version v1.0.0 agrega caracteristicas de robustez para produccion. Actualice sus definiciones de trabajos:

 schedule {
   name: "my-job"
   agent: "my-agent"
   cron: "0 0 * * * *"
+
+  # Agregar limite de concurrencia
+  max_concurrent: 2
+
+  # Agregar AgentPin para verificacion de identidad
+  agent_pin_jwt: "${AGENT_PIN_JWT}"
+
+  policy {
+    require_agent_pin: true
+  }
 }

Actualizar configuracion:

 [scheduler]
 tick_interval_seconds = 1
+ max_jitter_seconds = 30
+ default_max_retries = 3
+ shutdown_timeout_seconds = 60

Sin cambios de API incompatibles. Todos los trabajos de v0.9.0 continuan funcionando.