SQL Server Agent guarda el historial completo de ejecuciones de todos sus jobs en la base de datos del sistema msdb, pero la información viene en un formato poco amigable — fechas y horas como enteros separados, duraciones codificadas como HHMMSS sin separadores, y estados representados por números. Esta consulta traduce todo eso a algo legible, enfocado específicamente en pasos de tipo SSIS.
Tablas utilizadas
Tabla
Descripción
msdb.dbo.sysjobs
Definición de los jobs del Agente
msdb.dbo.sysjobsteps
Pasos de cada job (tipo, comando, etc.)
msdb.dbo.sysjobhistory
Historial de ejecuciones (fecha, duración, estado)
Las tres se relacionan por job_id (y step_id entre pasos e historial), ya que un job puede tener varios pasos, y cada paso acumula múltiples ejecuciones a lo largo del tiempo.
La query
USE msdb;GOSELECT j.name AS JobName, js.step_id AS StepNo, js.step_name AS StepName, js.subsystem AS StepType, -- 'SSIS' para paquetes SSIS js.command AS SSISCommand, -- ruta del paquete o comando-- Fecha y hora de inicio legibles msdb.dbo.agent_datetime(h.run_date, h.run_time) AS RunStart,-- Duración formateada HH:MM:SSSTUFF(STUFF(RIGHT(REPLICATE('0', 6) +CAST(h.run_duration ASVARCHAR(6)), 6),3, 0, ':'), 6, 0, ':') AS Duration_HHMMSS,-- Duración en segundos (para cálculos / ORDER BY) (h.run_duration /10000*3600)+ ((h.run_duration /100) % 100*60)+ (h.run_duration % 100) AS Duration_Seconds,-- Fecha fin estimadaDATEADD(SECOND, (h.run_duration /10000*3600)+ ((h.run_duration /100) % 100*60)+ (h.run_duration % 100), msdb.dbo.agent_datetime(h.run_date, h.run_time) ) AS RunEnd,CASE h.run_statusWHEN0THEN'Failed'WHEN1THEN'Succeeded'WHEN2THEN'Retry'WHEN3THEN'Cancelled'WHEN4THEN'In Progress'ENDAS RunStatus, h.message AS ResultMessage, j.enabled AS JobEnabledFROM msdb.dbo.sysjobs jJOIN msdb.dbo.sysjobsteps js ON js.job_id = j.job_idJOIN msdb.dbo.sysjobhistory h ON h.job_id = j.job_idAND h.step_id = js.step_idWHERE js.subsystem ='SSIS'-- AND j.enabled = 1 -- descomentar: solo jobs activos-- AND h.run_date >= 20250101 -- descomentar: filtrar por fecha (YYYYMMDD)ORDER BY j.name, msdb.dbo.agent_datetime(h.run_date, h.run_time) DESC;
Cómo funciona cada parte
Fecha y hora legibles
SQL Server Agent guarda run_date y run_time como dos enteros separados (por ejemplo 20260622 y 143000). La función del sistema msdb.dbo.agent_datetime() los combina y convierte a un DATETIME normal, evitando tener que parsear los enteros a mano.
Duración: de entero codificado a HH:MM:SS
run_duration también viene como entero, pero en formato HHMMSS concatenado (por ejemplo, 13045 significa 1 hora, 30 minutos, 45 segundos). El doble STUFF() rellena con ceros a la izquierda hasta 6 dígitos y luego inserta los dos puntos en las posiciones correctas, para que se lea como una duración real.
Duración en segundos
Para poder ordenar o hacer cálculos con la duración (algo que el formato HH:MM:SS como texto no permite bien), la query descompone el mismo entero run_duration en horas, minutos y segundos por separado usando división entera y módulo, y los suma todos convertidos a segundos.
Fecha de fin estimada
Como sysjobhistory solo guarda la hora de inicio y la duración (no la hora de fin), RunEnd se calcula sumando la duración en segundos (ya calculada arriba) a la fecha de inicio con DATEADD.
Estado de la ejecución
El campo run_status es un entero sin significado evidente por sí solo. El CASE lo traduce a los cinco estados posibles que maneja SQL Server Agent: Failed, Succeeded, Retry, Cancelled e In Progress.
Filtros opcionales
La query trae dos filtros comentados, útiles según el caso:
AND j.enabled = 1 — descomentar para ver únicamente jobs que están activos actualmente (excluye jobs deshabilitados que quedaron en el historial).
AND h.run_date >= 20250101 — descomentar para acotar el historial a partir de una fecha específica, en formato YYYYMMDD. Útil en instancias con mucho tiempo de historial acumulado, donde la consulta completa puede ser lenta.
Variante: solo las ejecuciones fallidas
Para monitoreo o alertas, suele ser más útil filtrar directamente por las ejecuciones que fallaron, en vez de traer todo el historial:
-- Agregar a la cláusula WHERE de la query original:AND h.run_status =0-- solo ejecuciones fallidas
Notas
run_duration está en formato HHMMSS como entero — requiere conversión manual, no es un tipo de dato de duración nativo.
agent_datetime(run_date, run_time) convierte los campos enteros a DATETIME legible.
Los filtros opcionales comentados permiten activar jobs y/o rango de fechas según la necesidad puntual de cada consulta.
Systemd es el sistema de inicialización y gestor de servicios usado por la mayoría de distribuciones Linux modernas (Debian, Ubuntu, Fedora, RHEL, Arch). Además de arrancar el sistema, systemd centraliza el control de casi todos los aspectos de administración a través de un conjunto de herramientas con el sufijo ctl («control»):
Servicios (.service) — procesos que corren en segundo plano.
Timers (.timer) — el reemplazo moderno de cron.
Sockets (.socket) — activación de servicios bajo demanda al recibir conexiones.
Targets — agrupaciones de unidades, equivalentes a los «runlevels» de SysV.
Logs (journal) — el sistema centralizado de registro de eventos.
Sesiones (loginctl) — gestión de sesiones de usuario.
Fecha/hora (timedatectl), hostname (hostnamectl), locales (localectl), red (networkctl) y DNS (resolvectl).
Bootloader (bootctl) y contenedores (machinectl, systemd-nspawn).
Crear servicios systemd
Estructura de un servicio
Un servicio personalizado se define en un archivo .service, típicamente dentro de /etc/systemd/system/:
[Unit] — metadatos y dependencias. After controla el orden de arranque (espera a que ocurra el evento indicado), mientras Wants expresa una dependencia flexible: si la red no está disponible, el servicio arranca igual, solo que después.
[Service] — cómo se ejecuta el proceso. Type=simple asume que el proceso principal no hace fork; ExecStart es el comando real; Restart=on-failure hace que systemd reinicie el servicio automáticamente si termina con un código de error (no en un cierre limpio); RestartSec es la pausa antes de reintentar.
[Install] — define en qué target se activa el servicio al hacer enable. multi-user.target es el equivalente al runlevel 3 clásico (sistema multiusuario, sin entorno gráfico).
Procedimiento universal
Flujo estándar para crear, activar y verificar cualquier servicio nuevo:
daemon-reload es el paso que más se olvida: systemd cachea las definiciones de las unidades en memoria, así que cualquier cambio al archivo .service no se aplica hasta ejecutar este comando. enable crea el enlace simbólico que hace que el servicio arranque automáticamente en el próximo boot — start solo lo arranca ahora, una vez.
Logs con journalctl
El journal es el sistema de logs binario centralizado de systemd — reemplaza (o complementa) a los archivos de texto tradicionales en /var/log/.
journalctl-umi-servicio# logs de un servicio específicojournalctl-umi-servicio-f# seguimiento en vivo (equivalente a tail -f)journalctl-umi-servicio-perr# solo mensajes de nivel error o más gravejournalctl-umi-servicio-b# logs desde el arranque actual del sistemajournalctl-xe# últimas líneas con contexto extendido, útil tras un fallo
Comandos *ctl del ecosistema systemd
systemctl — control de unidades
La herramienta principal para gestionar el estado de servicios y otras unidades:
systemctlstartnombre# arrancar ahorasystemctlstopnombre# detener ahorasystemctlrestartnombre# detener y volver a arrancarsystemctlreloadnombre# recargar configuración sin reiniciar el procesosystemctlenablenombre# activar en el próximo bootsystemctldisablenombre# desactivar en el próximo bootsystemctlstatusnombre# ver estado actual y últimos logssystemctllist-units# listar unidades cargadas actualmentesystemctllist-unit-files# listar todas las unidades instaladas (activas o no)systemctldaemon-reload# releer definiciones de unidades tras editarlassystemctlisolatemulti-user.target# cambiar de target activo (similar a cambiar runlevel)systemctl--failed# listar únicamente las unidades que fallaron
journalctl — consultas adicionales al journal
journalctl# todo el log disponiblejournalctl-f# seguimiento en vivo de todo el sistemajournalctl-xe# contexto extendido de los eventos más recientesjournalctl-perr# filtrar por severidad (err, warning, crit, etc.)journalctl-unombre# logs de una unidad específicajournalctl-b# logs solo del arranque actualjournalctl-k# solo mensajes del kernel (equivalente a dmesg)journalctl--since"2026-01-01"# filtrar por fecha
loginctl — sesiones de usuario
Gestiona sesiones activas, útil en servidores multiusuario o para depurar sesiones colgadas:
loginctllist-sessions# ver todas las sesiones activasloginctlsession-status3# detalle de una sesión específicaloginctlterminate-session3# cerrar una sesión a la fuerzaloginctllist-users# usuarios con sesión activaloginctluser-statususuario# detalle de sesiones de un usuariologinctlenable-lingerusuario# permite que los servicios de usuario (systemd --user) sigan corriendo aunque cierre sesión
timedatectl — fecha, hora y NTP
timedatectl# ver configuración actualtimedatectlset-time"2026-06-30 10:00:00"# fijar hora manualmentetimedatectlset-timezoneAmerica/Guayaquil# cambiar zona horariatimedatectlset-ntptrue# activar sincronización automática por NTP
hostnamectl — nombre del equipo
hostnamectl# ver hostname y datos del sistema (kernel, arquitectura, etc.)hostnamectlset-hostnameservidor# cambiar el hostname de forma persistente
localectl — idioma y teclado
localectl# ver configuración de locale actuallocalectlset-localeLANG=es_EC.UTF-8# cambiar idioma del sistemalocalectlset-keymapus# cambiar distribución de teclado
networkctl — estado de interfaces de red
Solo aplica en sistemas que usan systemd-networkd como gestor de red (no todos — muchas distros usan NetworkManager o ifupdown en su lugar):
networkctl# listar interfaces y su estadonetworkctlstatuseth0# detalle de una interfaz específicanetworkctllist# listado resumidonetworkctlreload# releer configuración de red
resolvectl — resolución DNS
resolvectlstatus# ver servidores DNS configurados por interfazresolvectlquerygoogle.com# hacer una consulta DNS de pruebaresolvectlflush-caches# limpiar la caché de resolución DNSresolvectldnseth08.8.8.8# fijar un DNS específico para una interfaz
machinectl — contenedores y máquinas virtuales ligeras
Gestiona contenedores creados con systemd-nspawn:
machinectllist# ver contenedores registradosmachinectlstartdebian# arrancar un contenedormachinectlstopdebian# detenerlomachinectlshelldebian# abrir una shell dentro del contenedor
bootctl — gestor de arranque (systemd-boot)
bootctlstatus# ver estado del bootloaderbootctlinstall# instalar systemd-boot en la partición EFIbootctlupdate# actualizar los binarios del bootloader
systemd-analyze — rendimiento de arranque
Herramienta de diagnóstico para entender qué tarda en el proceso de boot:
systemd-analyze# tiempo total de arranque, desglosado por fasesystemd-analyzeblame# qué servicios tardaron más en iniciarsystemd-analyzecritical-chain# cadena de dependencias que determinó el tiempo totalsystemd-analyzeplot>boot.svg# generar un gráfico visual del arranque
systemd-run — ejecutar comandos como unidades temporales
Permite lanzar cualquier comando como si fuera un servicio administrado por systemd, sin crear un archivo .service permanente — útil para pruebas o tareas puntuales que necesitan aislamiento de recursos:
systemd-tmpfiles — gestión de archivos y directorios temporales
systemd-tmpfiles--create# crear archivos/directorios definidos en configuraciónsystemd-tmpfiles--clean# limpiar archivos temporales expiradossystemd-tmpfiles--remove# eliminar los definidos en configuración
Los timers son la alternativa moderna a cron, con la ventaja de integrarse con el journal (logs unificados) y con dependencias de otras unidades. Un timer siempre va acompañado de un servicio con el mismo nombre base.
Persistent=true es clave: si el equipo estuvo apagado cuando debía ejecutarse el timer, lo corre en cuanto vuelve a encender, en vez de esperar al siguiente ciclo — evita perder ejecuciones por reinicios o cortes de energía.
Type=oneshot le indica a systemd que el proceso termina por sí solo tras completar su tarea (no es un servicio de larga duración) — es el tipo correcto para scripts que corren, hacen su trabajo, y salen.
Secuencia típica para diagnosticar un servicio que no arranca o falla:
systemctlstatusmi-servicio# estado y últimas líneas de logjournalctl-umi-servicio-perr-b# solo errores, desde el último bootjournalctl-umi-servicio-n20# últimas 20 líneas de logjournalctl_PID=$(pidof mi-servicio)# logs filtrados por PID específicosystemctllist-dependenciesmi-servicio# árbol de dependenciassystemd-analyzeverify/etc/systemd/system/mi-servicio.service# validar sintaxis del archivosudo-uusuario/usr/bin/python3/opt/app/app.py# ejecutar manualmente como el mismo usuario, para ver el error realls-l/opt/app/app.py# confirmar que el archivo existe y tiene permisos correctosls-l/usr/bin/python3# confirmar que el binario existe en la ruta esperadacat/etc/default/app# revisar variables de entorno cargadassystemctldaemon-reload# por si el problema es una definición desactualizada
Muestra el símbolo de estado visual (● activo, ○ inactivo, ✗ falló, ▲ iniciando), el nombre técnico del servicio y su descripción legible.
Loaded
Indica si el archivo .service está cargado, su ruta completa, y el estado de instalación: enabled (arranca en boot), disabled (no arranca en boot pero se puede iniciar manualmente), static (no tiene sección [Install], solo se activa como dependencia de otra unidad), o masked (bloqueado explícitamente, no se puede iniciar ni siquiera manualmente).
Active
El estado real de ejecución: active (running), inactive (dead), failed, activating o deactivating (transiciones en curso), y reloading.
TriggeredBy
Indica qué otra unidad activó este servicio — típicamente un Timer, un Socket, o un Path (activación al detectar cambios en un archivo/directorio).
Process
Detalle del último proceso ejecutado: PID, comando exacto que se corrió, y el código de salida (exit code) — clave para saber si terminó bien (status=0/SUCCESS) o con error.
Main PID
El proceso principal identificado por el servicio, el que systemd supervisa para determinar si sigue vivo.
CPU
Tiempo total de CPU consumido por el servicio desde que arrancó.
Logs
Las últimas líneas del journal relacionadas con esta unidad, mostradas automáticamente al final del status.
Buenas prácticas
Usar siempre rutas absolutas en ExecStart — systemd no hereda el $PATH de una shell de usuario.
Restart=on-failure como valor por defecto razonable, para que el servicio se recupere solo ante caídas inesperadas.
After=network-online.target si el servicio depende de conectividad de red al arrancar (evita condiciones de carrera con la red, como las que resuelven un resolv.conf vacío en contenedores Docker al bootear antes que la red).
EnvironmentFile= para mantener configuraciones y secretos fuera del archivo .service en sí, en un archivo separado con permisos restringidos.
Monitorear en vivo con journalctl -u servicio -f al depurar o al desplegar cambios.
Nunca olvidar systemctl daemon-reload después de editar cualquier archivo .service o .timer.
Este sitio utiliza cookies esenciales para su funcionamiento. No usamos cookies de rastreo publicitario ni analytics de terceros.
Más información.