⬅️ Volver a la clase 171 · 🧬 Primos del Atlas · 🧟 Índice de lenguajes vivos · 📚 Índice
Ejecutar N tareas y decir que terminaron: tareas=5 estado=completado. Es un orquestador reducido a lo
esencial, y esta clase trata del componente que ningún diagrama dibuja y sin el cual no funciona nada.
Y aquí hay una precedencia clara: el JCL, de 1964, es un lenguaje de orquestación de trabajos con
dependencias, condiciones y asignación de recursos — y lo que hoy hacen Airflow, Argo o GitHub Actions
tiene una forma sorprendentemente parecida.
🎯 Estos lenguajes no están aquí por ser antiguos
El criterio es doble y se declara en la ficha de cada uno: que se ejecute hoy —banca, sanidad, aviónica, ERP, diseño de chips, CAD— y que deje a la vista un concepto que los diez del núcleo esconden.
Aquí el concepto es la automatización como componente de primera clase, y estos lenguajes la enseñan porque tienen los lenguajes de orquestación más antiguos y más probados: JCL en z/OS, CL en IBM i, y las herramientas que crecieron alrededor —Expect, Perl, Tcl— para automatizar lo que no tenía interfaz.
Y aparece la propiedad que separa una automatización que aguanta de una que se rompe cada semana: la idempotencia — que ejecutarla dos veces dé el mismo resultado que ejecutarla una.
Y ninguno es una foto fija: casi todos han incorporado en los últimos años JSON, REST, GPU, Unicode o Git. Cada ficha lo detalla en su sección
🔄 Lo que se ha modernizado.
n (número de tareas) → stdout: tareas=<n> estado=completadoprocesar n tareas y confirmar| stdin | esperado |
|---|---|
5 |
tareas=5 estado=completado |
0 |
tareas=0 estado=completado |
3 |
tareas=3 estado=completado |
Qué está verificado en esta página. Los lenguajes de la sección 🟢 se ejecutan en CI contra este mismo
casos.json, igual que las diez implementaciones del núcleo (workflow Labs). Los de la sección 🟡 no pueden cumplir este contrato sin falsear el lenguaje, y se explica por qué. Los de la sección ⚪ sí podrían, pero su cadena de herramientas no está en los runners: son correctos, sin sello de máquina.
Ficha completa · Banca, seguros, gobierno, medios de pago · cobc -x -free prog.cob
IDENTIFICATION DIVISION.
PROGRAM-ID. AUTOMAT.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 LINEA PIC X(40).
01 N PIC S9(9) COMP.
01 ED PIC -(8)9.
PROCEDURE DIVISION.
ACCEPT LINEA
COMPUTE N = FUNCTION NUMVAL(LINEA)
MOVE N TO ED
DISPLAY "tareas=" FUNCTION TRIM(ED) " estado=completado"
STOP RUN.
COBOL y la automatización. Aquí está el dato del gancho, y merece verlo con la lista de propiedades del cierre delante: el JCL es un lenguaje de orquestación (clase 077).
//NOCTURNO JOB CLASS=B,MSGCLASS=X,RESTART=PASO3
//PASO1 EXEC PGM=EXTRAER
//SALIDA DD DSN=&&TEMP,DISP=(NEW,PASS)
//PASO2 EXEC PGM=VALIDAR,COND=(0,LT,PASO1)
//PASO3 EXEC PGM=CALCULAR,COND=(8,LE)
//PASO4 EXEC PGM=INFORMAR,COND=EVEN
Y las tres propiedades del cierre están ahí:
RESTART=PASO3 es la reanudabilidad: el trabajo se relanza desde el paso que falló, sin repetir
los anteriores.
COND= es el control de flujo: cada paso se ejecuta o se salta según los códigos de retorno de los
anteriores (clase 167). COND=EVEN significa "ejecuta aunque algo haya fallado" — el paso de
limpieza.
Y el registro es automático (clase 142): el registro del trabajo recoge cada paso, su código, su consumo y sus mensajes.
Y hay una cuarta propiedad que el JCL tiene y que las herramientas modernas suelen no tener, y merece destacarse: la declaración de recursos.
//SALIDA DD DSN=MI.FICHERO,DISP=(NEW,CATLG),SPACE=(CYL,(100,50)),
// UNIT=SYSDA,VOL=SER=WORK01
El trabajo declara cuánto espacio necesita y qué ficheros va a usar, ANTES de arrancar, y el planificador puede negarse a lanzarlo si no hay sitio.
Eso evita el fallo más frustrante de un proceso largo: reventar a las cuatro horas por falta de espacio.
Es una idea que los orquestadores modernos han recuperado con las peticiones de recursos de los contenedores, y por la misma razón.
Y sobre los planificadores, merece nombrarlos porque son el componente real de esta clase en estos sistemas: Control-M, CA-7, TWS — herramientas que gestionan decenas de miles de trabajos al día con dependencias entre sí, calendarios, ventanas y avisos.
Es Airflow, con cuarenta años y a otra escala.
Ficha completa · HPC, clima, física, BLAS/LAPACK · gfortran -O2 prog.f90
program automat
implicit none
integer :: n
read(*, *) n
write(*, '(A,I0,A)') 'tareas=', n, ' estado=completado'
end program automat
Fortran y la automatización. El cálculo científico tiene su propio orquestador, y merece conocerlo porque su modelo es distinto: el planificador del clúster.
#!/bin/bash
#SBATCH --job-name=simulacion
#SBATCH --nodes=64
#SBATCH --ntasks-per-node=48
#SBATCH --time=24:00:00
#SBATCH --dependency=afterok:12345 # ← ¡dependencias entre trabajos!
#SBATCH --array=1-100 # ← 100 variantes del mismo trabajo
srun ./simulacion --caso $SLURM_ARRAY_TASK_ID
SLURM, PBS y LSF reparten un superordenador entre cientos de usuarios, y merece señalar lo que resuelven:
| Capacidad | Detalle |
|---|---|
| Cola con prioridades y cuotas | quién entra antes, y cuánto puede consumir |
| Reserva de recursos | 64 nodos durante 24 horas, garantizados |
| Dependencias | afterok, afterany: el JCL de esta página |
| Arreglos de trabajos | cien variantes con una sola línea |
| Y límite de tiempo duro | el trabajo se mata al agotarlo |
La cuarta fila es la que resuelve el problema de la clase 167: un barrido de parámetros es
--array, siempre que el programa acepte el caso por la línea de comandos.
Y la quinta trae la propiedad del cierre que este dominio necesita más que ninguno: la reanudabilidad.
Un cálculo de 200 horas no cabe en un límite de 24.
Así que el programa GUARDA PUNTOS DE CONTROL y se relanza:
- cada N pasos escribe su estado completo
- y al arrancar, si encuentra un punto de control, continúa desde ahí
Y esa capacidad hay que diseñarla dentro del programa: no la puede añadir el planificador.
Es la segunda propiedad del cierre, y en este dominio es un requisito de arquitectura del componente de cálculo, no una comodidad — porque sin ella, cualquier fallo cuesta la ejecución entera.
Ficha completa · Aviónica, espacio, ferrocarril, defensa · gnatmake prog.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Strings;
with Ada.Strings.Fixed;
procedure Automat is
N : Integer;
begin
Get (N);
Put_Line ("tareas=" & Ada.Strings.Fixed.Trim (N'Image, Ada.Strings.Both) &
" estado=completado");
end Automat;
Ada y la automatización. Ada no es un lenguaje de guiones, y esta clase es el sitio para lo que sí aporta a este componente: la automatización de la construcción y la verificación (clase 147).
gprbuild -P proyecto.gpr -XMODO=produccion
gnatcheck -P proyecto.gpr
gnattest -P proyecto.gpr && ./obj/test_runner
gnatprove -P proyecto.gpr --level=2
gnatcoverage --level=stmt+mcdc
Y en un proyecto certificado, esa secuencia no es una comodidad: es parte del expediente — cada ejecución se archiva con su resultado, porque hay que demostrar ante un auditor que se hizo (clase 144).
Y merece señalar lo que eso impone y que es la tercera propiedad del cierre llevada al extremo: la automatización tiene que dejar constancia.
No basta con que la construcción pase.
Hay que conservar:
- qué versión exacta del fuente se usó
- qué versión de cada herramienta
- qué opciones
- y los informes completos, firmados
Es la lista de materiales de la clase 144, producida por la automatización y conservada durante la vida del producto — que en aviación son treinta años o más.
Y hay una propiedad de Ada que merece nombrarse porque hace la automatización mucho más fiable y que la clase 149 explicó: el fichero de proyecto es la única fuente de la configuración.
project Proyecto is
type Modo_Tipo is ("desarrollo", "produccion");
Modo : Modo_Tipo := external ("MODO", "desarrollo");
package Compiler is
case Modo is
when "desarrollo" => for Default_Switches ("Ada") use ("-g", "-gnata");
when "produccion" => for Default_Switches ("Ada") use ("-O2");
end case;
end Compiler;
end Proyecto;
Las opciones no están repartidas entre un guion, un Makefile y la memoria de alguien: están declaradas, con las variantes explícitas.
Y eso resuelve el problema de reproducibilidad más común (clase 144): que el binario dependa de cómo lo compiló quien lo compiló.
Ficha completa · Escritorio empresarial, TPV, industria (vía Delphi y Free Pascal) · fpc -Mobjfpc prog.pas
program Automat;
{$MODE OBJFPC}{$H+}
uses SysUtils;
var
N: Integer;
begin
Read(N);
WriteLn('tareas=', IntToStr(N), ' estado=completado');
end.
Pascal y la automatización. Free Pascal es una buena elección para el componente de automatización por la razón de la clase 167: produce herramientas pequeñas, rápidas y sin dependencias.
uses Process, SysUtils;
function Ejecutar(const Cmd: string; const Args: array of string;
out Salida: string): Integer;
begin
Result := -1;
with TProcess.Create(nil) do
try
Executable := Cmd;
Parameters.AddStrings(Args); { ← lista, no cadena (clase 153) }
Options := [poWaitOnExit, poUsePipes];
Execute;
Salida := ...;
Result := ExitStatus; { ← el código de retorno }
finally
Free;
end;
end;
Parameters como lista y no como cadena es la defensa contra la inyección de comandos, igual que en
Perl (clase 161).
Y merece dedicar el resto a la primera propiedad del cierre, porque es la que menos se aplica y la que más problemas evita: la idempotencia.
{ ✗ no idempotente: al reintentar, duplica }
AppendFile(Registro, Linea);
{ ✓ idempotente: comprobar antes de actuar }
if not FileExists(Destino) then CopyFile(Origen, Destino);
if not DirectoryExists(Ruta) then ForceDirectories(Ruta);
Y la forma general, que sirve en cualquier lenguaje: escribir a un temporal y renombrar.
Guardar(Destino + '.tmp');
RenameFile(Destino + '.tmp', Destino); { ← atómico en el mismo sistema de ficheros }
El renombrado es atómico, así que el fichero de destino nunca existe a medias — y si el proceso muere a mitad, no deja un fichero corrupto, deja un temporal que se puede borrar.
Es el mismo patrón del enlace simbólico del despliegue (clase 148), y es probablemente la técnica más rentable de toda esta clase: convierte una operación que puede dejar el sistema en un estado intermedio en una que no.
Ficha completa · IA simbólica, CAD, investigación · sbcl --script prog.lisp
(let ((n (read)))
(format t "tareas=~D estado=completado~%" n))
Lisp y la automatización. Lisp tiene, para este componente, una capacidad que su modelo hace natural: la automatización puede ser código de primera clase, no cadenas.
(defparameter *plan*
'((:extraer :de "origen" :a "temp")
(:validar :sobre "temp" :requiere (:extraer))
(:calcular :sobre "temp" :requiere (:validar))
(:informar :requiere (:calcular) :siempre t)))
(ejecutar-plan *plan*)
El plan es una estructura de datos, así que se puede inspeccionar, validar, transformar y visualizar antes de ejecutarlo — cosa que un guion de shell no permite.
Y esa propiedad merece destacarse porque es la que separa un orquestador de un guion: un plan declarado se puede analizar.
(detectar-ciclos *plan*) ; ¿hay dependencias circulares?
(orden-topologico *plan*) ; ¿en qué orden hay que ejecutarlo?
(que-falta-si-falla :validar) ; ¿qué se salta?
Es exactamente lo que Airflow y Make hacen con su grafo, y en Lisp la estructura ya es un dato.
Y el ecosistema para el componente práctico:
| Herramienta | Notas |
|---|---|
| UIOP | run-program, rutas, variables de entorno — portable |
| ASDF | el sistema de construcción, con dependencias (clase 143) |
| Roswell | guiones ejecutables con #! |
cl-cron / hilos |
tareas periódicas dentro de un servicio |
Y merece cerrar con la propiedad de Lisp que hace la automatización más segura y que la clase 132
explicó: unwind-protect.
(unwind-protect
(progn (bloquear-recurso) (procesar))
(liberar-recurso)) ; ← se ejecuta SIEMPRE, aunque haya error o interrupción
Una automatización que reserva algo —un bloqueo, un directorio temporal, una conexión— tiene que
liberarlo pase lo que pase, y la mitad de los guiones de shell no lo hacen porque hay que escribir
un trap.
Es la tercera propiedad del cierre vista desde otro lado: una automatización que falla debe dejar el sistema en un estado conocido, no en el que estuviera.
Ficha completa · Diseño de chips (EDA), redes, testing · tclsh prog.tcl
gets stdin linea
set n [string trim $linea]
puts "tareas=$n estado=completado"
Tcl y la automatización. Este es el componente de Tcl por excelencia (clases 155 y 165), y esta clase es el sitio para juntar lo que las anteriores han ido nombrando.
# Ejecutar con control de errores y de tiempo
proc ejecutar {cmd args} {
set salida ""
set codigo [catch {exec {*}$cmd {*}$args} salida opciones]
if {$codigo} {
set info [dict get $opciones -errorcode]
if {[lindex $info 0] eq "CHILDSTATUS"} {
return -code error "falló con estado [lindex $info 2]: $salida"
}
return -code error $salida
}
return $salida
}
-errorcode con CHILDSTATUS da el código de salida del proceso hijo, distinguiendo "el programa
devolvió error" de "no se pudo ejecutar" — que son dos fallos distintos y casi ningún guion los separa.
Y Expect (clase 147) sigue siendo la respuesta cuando no hay API:
package require Expect
set timeout 30
spawn ssh operador@equipo
expect {
"password:" { send "$::env(CLAVE)\r"; exp_continue }
"$ " { send "reiniciar servicio\r" }
timeout { error "sin respuesta del equipo" }
}
Y la lección de Expect que la clase 147 anticipó es la primera propiedad del cierre aplicada a las esperas: esperar por un evento, no por un tiempo.
# ✗ frágil: depende de la carga de la máquina
after 5000
# ✓ robusto: espera a que ocurra algo, con un límite
esperarPuerto 8080 -timeout 30
Y merece cerrar señalando la propiedad que hace de Tcl un buen orquestador y que la clase 161 explicó: el bucle de eventos.
# Lanzar cinco tareas EN PARALELO y esperar a todas
foreach t $tareas {
set canal [open "|./tarea $t" r]
fconfigure $canal -blocking 0
fileevent $canal readable [list recogerSalida $canal]
incr pendientes
}
vwait pendientes
Paralelismo real sin hilos y sin bloquear, que es lo que un orquestador necesita: lanzar muchas cosas, recoger sus salidas y saber cuándo han terminado todas.
Ficha completa · Sysadmin, texto, bioinformática · perl prog.pl
use strict;
use warnings;
my $n = <STDIN>;
chomp $n;
print "tareas=$n estado=completado\n";
Perl y la automatización. Perl fue la herramienta de automatización de sistemas durante veinte años, y su ecosistema para este componente sigue siendo excelente:
use IPC::Run qw(run timeout);
use Try::Tiny;
use File::Temp qw(tempdir);
use Path::Tiny;
my $dir = tempdir(CLEANUP => 1); # ← se borra solo al salir
try {
run \@comando, \undef, \my $salida, \my $error, timeout(300)
or die "falló ($?): $error";
} catch {
warn "reintentando: $_";
...
};
tempdir(CLEANUP => 1) y timeout(300) son las dos piezas que más veces faltan en una
automatización: limpiar siempre y no esperar para siempre.
Y Perl aporta a esta clase la herramienta de automatización que definió una categoría entera y merece
nombrarse: rsync no, pero sí cfengine y sus descendientes.
La gestión de configuración —describir el estado deseado
en lugar de los pasos para llegar— nació en los años noventa,
y su idea central es la primera propiedad del cierre de esta clase.
# ✗ imperativo: los pasos. No es idempotente.
system('useradd', 'app');
system('mkdir', '/opt/app');
# ✓ declarativo: el estado deseado. Idempotente por construcción.
asegurar_usuario('app');
asegurar_directorio('/opt/app', modo => 0755);
Y "asegurar" es la palabra clave: comprueba y actúa solo si hace falta, así que ejecutar dos veces no cambia nada.
Es exactamente el modelo de Ansible, Puppet, Chef y Terraform, y es la aportación conceptual más importante de esta clase: describir el destino, no el camino.
Y merece cerrar con la advertencia del cierre que Perl ilustra bien, porque su facilidad la provoca: un guion de automatización crece hasta ser un sistema (clase 165).
Y en cuanto despliega, borra o mueve datos de producción, es código de producción: con pruebas, con revisión y con un modo de simulación.
GetOptions('dry-run' => \my $simular);
...
if ($simular) { say "haría: borrar $ruta" } else { unlink $ruta }
El modo de simulación es la característica más valiosa de una herramienta de automatización, y la que permite revisar un cambio grande antes de ejecutarlo.
Ficha completa · Videojuegos, navegadores, finanzas, HPC · g++ -std=c++17 prog.cpp
#include <iostream>
int main() {
long long n{};
if (!(std::cin >> n)) return 1;
std::cout << "tareas=" << n << " estado=completado" << '\n';
return 0;
}
C++ y la automatización. C++ no se usa para escribir guiones, y esta clase es el sitio para lo que sí aporta: es el lenguaje de las herramientas que la automatización usa.
Sistemas de construcción: Ninja, CMake, Bazel (C++ y Java)
Contenedores: containerd, runc (Go), pero el núcleo es C
Orquestación: Kubernetes (Go), Envoy (C++)
Y las herramientas rápidas: ripgrep, fd (Rust), jq (C)
Y la razón es la de la clase 167: el tiempo de arranque.
Un sistema de construcción invoca herramientas MILES de veces.
Con 30 ms de arranque por invocación, 10.000 invocaciones son 5 minutos
de puro arranque.
Por eso las herramientas del camino crítico están compiladas, y por eso Ninja —escrito en C++ y diseñado para hacer una sola cosa— desplazó a Make en proyectos grandes.
Y C++ aporta a esta clase la biblioteca que la clase 147 agradece y que merece nombrar: std::filesystem
(C++17), que hizo portables las operaciones de ficheros.
#include <filesystem>
namespace fs = std::filesystem;
fs::create_directories(destino); // idempotente por definición
fs::copy_file(a, b, fs::copy_options::overwrite_existing);
for (const auto& e : fs::recursive_directory_iterator(raiz)) { ... }
std::error_code ec;
fs::remove_all(temporal, ec); // sin excepción: con código
create_directories no falla si ya existe, que es la primera propiedad del cierre integrada en la
API — y merece señalarlo porque es la diferencia entre una API que empuja a la idempotencia y una que no.
Y la sobrecarga con std::error_code merece la mención por la tercera propiedad: en una automatización,
un fallo esperado —el fichero no está— no debería lanzar; y uno inesperado, sí.
Distinguir los dos es lo que hace que el registro sea útil en lugar de una lista de excepciones donde no se sabe cuál importaba.
Estos lenguajes no pueden leer de stdin y escribir en stdout sin dejar de ser ellos
mismos. No es una limitación del material: es su naturaleza. El cálculo es el mismo y la forma
de entrar y salir es la de su anfitrión. No pasan por el verificador, y se dice.
Ficha completa · IBM i: ERP, retail, logística, manufactura · CRTBNDRPG sobre IBM i
En IBM i un programa recibe sus datos por parámetros, por un fichero o por una pantalla, nunca por la entrada estándar.
**free
ctl-opt dftactgrp(*no) actgrp(*caller);
dcl-pi AUTOMAT;
n int(10) const;
end-pi;
dsply ('tareas=' + %char(n) + ' estado=completado');
*inlr = *on;
return;
RPG y la automatización. IBM i tiene su propio lenguaje de orquestación, hermano del JCL y bastante más agradable: CL, el Control Language.
PGM
DCL VAR(&FECHA) TYPE(*CHAR) LEN(8)
MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR)) /* ← manejo de errores GLOBAL */
RTVSYSVAL SYSVAL(QDATE) RTNVAR(&FECHA)
CALL PGM(EXTRAER) PARM(&FECHA)
CALL PGM(CALCULAR) PARM(&FECHA)
SBMJOB CMD(CALL PGM(INFORMAR)) JOB(INFORME) /* ← en segundo plano */
RETURN
ERROR:
SNDMSG MSG('Falló el proceso nocturno') TOUSR(*SYSOPR)
MONMSG MSGID(CPF0000)
ENDPGM
Y merece destacar tres cosas porque son las propiedades del cierre:
MONMSG es manejo de errores declarado para todo el programa —o para el comando anterior— y eso
hace que un guion CL no siga adelante en silencio tras un fallo, que es el problema clásico de los
guiones de shell sin set -e.
SBMJOB envía trabajo al planificador, con su cola, su prioridad y su descripción — así que la
ejecución en segundo plano es del sistema, con su registro (clase 142).
Y el planificador del sistema —ADDJOBSCDE— da las tareas periódicas, con calendario y con
control de si el trabajo anterior sigue corriendo.
Y esta clase debe recoger la propiedad que esta plataforma da y que hace la automatización mucho más segura: el registro completo de cada trabajo (clase 142).
DSPJOBLOG del trabajo nocturno:
cada comando ejecutado, sus parámetros, sus mensajes y su resultado.
Sin instrumentar nada.
Es la tercera propiedad del cierre resuelta por la plataforma, y hace que diagnosticar un proceso nocturno que falló a las 3:40 sea mirar un registro, en lugar de deducirlo de lo que quedó a medias.
Sí podrían cumplir el contrato, pero su cadena de herramientas no está en los runners de CI.
Ficha completa · Mainframe z/OS: banca, seguros · IBM Enterprise PL/I for z/OS
automat: procedure options(main);
declare n fixed binary(31);
get list (n);
put skip list ('tareas=' || trim(char(n)) || ' estado=completado');
end automat;
PL/I y la automatización. PL/I comparte el JCL con COBOL en esta página, y esta clase es el sitio para la pieza que hace de orquestador de verdad en estos sistemas: el planificador de trabajos.
Control-M, CA-7, IBM Workload Scheduler gestionan:
- decenas de miles de trabajos al día
- con dependencias entre ellos, entre sistemas y entre máquinas
- calendarios: laborables, fin de mes, festivos por país
- ventanas de ejecución y recursos exclusivos
- reintentos automáticos y escalado de avisos
- y una vista del plan completo del día
Y esa lista es, casi palabra por palabra, la de un orquestador moderno — con dos diferencias que merecen señalarse porque van en direcciones opuestas:
A favor de los antiguos: el calendario de negocio. Un planificador de mainframe sabe qué es "el tercer día hábil del mes", "el cierre trimestral" y "los festivos de cada país donde opera el banco" — y eso, que suena trivial, es la mitad de la lógica de un proceso financiero y las herramientas modernas lo suelen dejar al usuario.
A favor de los modernos: el plan está en el repositorio. Un DAG de Airflow o un fichero de GitHub Actions se versiona, se revisa y se despliega (clase 145); la definición en un planificador clásico vive en su propia base de datos, se edita por pantalla y no está en git.
Y esa segunda diferencia es exactamente la advertencia del cierre de esta clase: la automatización es código de producción.
Cuando el plan de ejecución de mil trabajos vive fuera del control de versiones, nadie sabe quién lo cambió ni por qué — y es una de las deudas técnicas más caras y menos reconocidas de estos sistemas (clase 154).
Y la práctica que lo corrige y que varias organizaciones han adoptado: exportar las definiciones del planificador a ficheros y versionarlas, aunque la herramienta no lo haga sola.
Ficha completa · Sanidad: historia clínica, VistA, Epic · YottaDB
AUTOMAT ; Componente de automatizacion -- clase 171
read n
write "tareas=", n, " estado=completado", !
quit
M y la automatización. VistA tiene un planificador propio dentro del sistema, y merece conocerlo porque su diseño encaja con el modelo de M: TaskMan.
; Programar una tarea
set ZTRTN = "PROCESAR^MIRUT"
set ZTDTH = $horolog ; cuándo
set ZTDESC = "Proceso nocturno de altas"
set ZTSAVE("VAR*") = "" ; qué variables se le pasan
do ^%ZTLOAD
Y la propiedad que lo distingue es la de la clase 161: la cola de tareas es una global.
Consecuencias:
- la tarea programada es PERSISTENTE: sobrevive a un reinicio
- se puede consultar, cancelar y reprogramar con SQL... o con $order
- y la programación participa de la TRANSACCIÓN que la creó
La tercera merece el detalle: si una transacción crea una tarea y luego se deshace, la tarea tampoco se crea.
Es el problema de la doble escritura de la clase 161 resuelto de raíz, y es una propiedad que un planificador externo no puede tener.
Y ZTSAVE merece la mención porque resuelve algo específico de M: el ámbito global por defecto (clase
146). La tarea se ejecuta en otro proceso, con otro espacio de variables, así que hay que declarar
explícitamente qué se le lleva.
Y eso, que parece una molestia, es exactamente la primera propiedad del cierre: la tarea recibe todo lo que necesita y no depende del estado del proceso que la creó, así que se puede reejecutar.
Y esta clase debe recoger la práctica de este dominio que la criticidad impone y que merece transferirse: la automatización clínica avisa a personas.
Un proceso que falla no escribe solo en un registro:
- envía un mensaje a la cola del operador
- y si es crítico, activa un aviso que alguien tiene que reconocer
Una automatización que falla en silencio es peor que no tenerla, porque todo el mundo cree que se está haciendo — y esa es la forma más peligrosa de la tercera propiedad del cierre incumplida.
Ficha completa · Banca, seguros, trading · Pharo
| n |
n := stdin nextLine trimBoth asNumber.
Transcript show: 'tareas=', n printString, ' estado=completado'; cr.
Smalltalk y la automatización. Smalltalk tiene, para este componente, una capacidad que su modelo hace natural: la tarea programada es un objeto vivo dentro del sistema.
"Una tarea periódica, dentro de la imagen"
tarea := [ [ true ] whileTrue: [
self procesarPendientes.
(Delay forSeconds: 60) wait ] ] newProcess.
tarea name: 'procesador'; priority: Processor userBackgroundPriority.
tarea resume.
Y la propiedad interesante es la de la Parte 8: se puede inspeccionar en marcha (clase 141).
Processor "todos los procesos, su estado y su prioridad"
tarea suspend. tarea resume. tarea terminate.
tarea suspendedContext "¡y ver DÓNDE está parada!"
Poder mirar dónde está bloqueada una tarea programada, en producción, sin haberlo previsto es algo que en la mayoría de los sistemas requiere volcados y suerte.
Y el ecosistema tiene lo que falta:
| Herramienta | Notas |
|---|---|
| TaskIt | tareas con conjunto de trabajadores y futuros |
Delay / Process |
lo básico, en el sistema |
| OSSubprocess / LibC | lanzar procesos externos |
| Iceberg + guiones Pharo | automatizar la construcción (clase 147) |
Y merece cerrar esta clase con la advertencia que el modelo de imagen impone y que es la primera propiedad del cierre en su versión más difícil: una tarea dentro de la imagen comparte su destino.
Si la imagen se reinicia, las tareas programadas DESAPARECEN
—salvo que se vuelvan a crear al arrancar—.
Y si una tarea corrompe el estado, lo corrompe para todos.
Así que la programación tiene que reconstruirse al arrancar, desde una descripción persistente:
Smalltalk at: #Programacion put: (OrderedCollection new).
"y en el arranque de la imagen:"
Programacion do: [ :cada | cada iniciar ].
Es la misma conclusión que M en esta página, con otro vocabulario: la definición de lo que hay que hacer tiene que sobrevivir al proceso que lo hace — y eso significa que vive en un almacén persistente, no en la memoria del que lo ejecuta.
Lo transferible: una automatización que no se puede volver a ejecutar sin miedo no está terminada. De ahí las tres propiedades que hay que buscar: idempotencia, para poder reintentar; reanudabilidad, para no repetir lo caro cuando falla el paso siete; y registro de lo que hizo, porque una automatización silenciosa es imposible de diagnosticar (clase 142). Y la advertencia que más caro sale ignorar: el código de automatización es código de producción — se versiona, se revisa y se prueba, porque es lo que despliega, borra y mueve datos.
⏮️ Volver a la clase 171 · 🧬 Los primos del Atlas · 🧟 Índice de lenguajes vivos