Comprueba una página o API pública cada 15 minutos, haz que el agente informe de lo que encuentra como JSON y publica en Slack solo cuando cambie el estado. Ephemeral ejecuta la comprobación según una programación; un pequeño script tuyo lee el resultado y decide si avisar.
Una comprobación que obtiene una página tarda unos 20 segundos. La mayor parte del coste es el cómputo, que se factura a $0.0002 por segundo, más $0.001 por obtener la página. La parte del modelo depende del modelo que elijas, así que lee cost_micros en las primeras ejecuciones y ajusta desde ahí la programación o el modelo.
Reúne lo que necesitas
- Una clave de API con el rol de administrador, porque solo los propietarios y administradores pueden crear programaciones. Consulta roles y claves.
- La página o API que vigilar, en un solo dominio, aquí
https://status.example.com. - Una URL de webhook entrante de Slack, o la dirección de tu propio servicio de alertas.
- Un lugar donde ejecutar un script cada pocos minutos: cron, un trabajo de CI programado o un temporizador serverless.
Guarda el flujo de trabajo
El flujo de trabajo obtiene la página y responde con una forma JSON fija. Ephemeral no impone un esquema de salida: la salida de la ejecución es texto libre. Por eso el prompt pide solo JSON, y tu script lo analiza con cautela en el paso 4.
curl -X PUT $EPHEMERAL_URL/v1/workflows/check-status-page \ -H "Authorization: Bearer $EPHEMERAL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Fetch the page at input.url with web_fetch. Reply with one JSON object and nothing else: {\"ok\": boolean, \"http_status\": number, \"summary\": string}. Set ok to true only when the response status is 200 and the page reports no ongoing incident, outage or degraded service; resolved past incidents do not count. summary is one sentence of at most 200 characters.", "web": { "allow": ["status.example.com"], "search": false }, "shell": false, "timeout_seconds": 90 }'El acceso web se limita a
status.example.comy la búsqueda está desactivada, así que la comprobación puede leer ese sitio y nada más. La URL que comprobar llega como entrada, de modo que el mismo flujo de trabajo puede servir a más de una programación en ese dominio.Crea la programación
Primero previsualiza el calendario. Devuelve las cinco próximas horas de inicio y no guarda nada.
curl -X POST $EPHEMERAL_URL/v1/schedules/preview \ -H "Authorization: Bearer $EPHEMERAL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "cron": "*/15 * * * *", "timezone": "UTC" }'Después créala. La entrada y el presupuesto son los mismos en cada ejecución.
curl -X POST $EPHEMERAL_URL/v1/schedules \ -H "Authorization: Bearer $EPHEMERAL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "workflow": "check-status-page", "name": "Status page, every 15 minutes", "cron": "*/15 * * * *", "input": { "url": "https://status.example.com" }, "max_cost_micros": 100000 }'Guarda el
idde la programación. El presupuesto de 100,000 micros ($0.10) se reserva de tus créditos en cada inicio y se libera cuando la ejecución se liquida; debe cubrir el cómputo del tiempo límite completo, que aquí son 90 segundos, $0.018. Si una comprobación sigue en marcha cuando toca el siguiente inicio, ese inicio se omite, porqueskip_if_runningestruepor defecto.Inicia una ahora y lee la respuesta
No esperes al calendario.
POST /v1/schedules/{id}/runinicia el flujo de trabajo ahora con la entrada y el presupuesto de la programación y responde202con una ejecución que lleva el ID de la programación. Después lista las ejecuciones de la programación, de la más reciente a la más antigua:curl -X POST $EPHEMERAL_URL/v1/schedules/$SCHEDULE_ID/run \ -H "Authorization: Bearer $EPHEMERAL_API_KEY" curl "$EPHEMERAL_URL/v1/runs?schedule=$SCHEDULE_ID&limit=1" \ -H "Authorization: Bearer $EPHEMERAL_API_KEY"outputes una cadena que contiene el JSON. A veces los modelos lo envuelven en un bloque de código o añaden una frase a pesar de la instrucción, así que el script de abajo toma todo desde la primera{hasta la última}y analiza eso.Avisa solo cuando algo cambie
Las ejecuciones programadas no envían callbacks, así que tu script pide en su lugar la ejecución más reciente de la programación. Recuerda la última ejecución y el último estado en un archivo, ignora las ejecuciones que ya vio o que siguen en marcha, y publica en Slack solo cuando el estado difiere del anterior. Una comprobación que falla o devuelve algo ilegible cuenta como un estado propio,
unknown, de modo que un monitor roto no se confunda con una página sana.import { readFile, writeFile } from "node:fs/promises"; const { EPHEMERAL_URL, EPHEMERAL_API_KEY, SCHEDULE_ID, SLACK_WEBHOOK_URL } = process.env; const ACTIVE = new Set(["reserving", "queued", "starting", "running"]); const stateFile = "monitor-state.json"; const state = JSON.parse(await readFile(stateFile, "utf8").catch(() => "{}")); const response = await fetch(`${EPHEMERAL_URL}/v1/runs?schedule=${SCHEDULE_ID}&limit=1`, { headers: { Authorization: `Bearer ${EPHEMERAL_API_KEY}` }, }); if (!response.ok) throw new Error(`Ephemeral returned ${response.status}`); const [run] = (await response.json()).items; if (!run || ACTIVE.has(run.status) || run.id === state.run) process.exit(0); // nothing new to judge let label = "unknown"; // the check itself did not produce an answer let summary = run.error ?? `The run ${run.status}.`; if (run.status === "succeeded") { try { const result = JSON.parse(run.output.match(/\{[\s\S]*\}/)[0]); // tolerate text or a code fence around the JSON label = result.ok === true ? "ok" : "down"; summary = result.summary; } catch { summary = "The check did not return valid JSON."; } } if (label !== (state.label ?? "ok")) { await fetch(SLACK_WEBHOOK_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ text: `Status page: ${label}. ${summary} (${run.id})` }), }); } await writeFile(stateFile, JSON.stringify({ run: run.id, label }));Ejecútalo cada cinco minutos, por ejemplo con
*/5 * * * *en cron, con las cuatro variables definidas. La primera comprobación no avisa si la página está sana; cada cambio posterior, incluida la recuperación dedownaok, publica una vez.
Conviene saber
| Tema | Comportamiento |
|---|---|
| Comprobaciones solapadas | Con skip_if_running activado, un inicio se omite mientras la ejecución anterior sigue en marcha, y la programación lo anota en last_error. Establécelo en false solo si el solapamiento es inofensivo. |
| Una programación que se detiene | Tras cinco inicios fallidos seguidos, por ejemplo porque se agotaron los créditos, la programación se desactiva sola y no aparecen ejecuciones nuevas. Comprueba enabled y last_error con GET /v1/schedules/{id} de vez en cuando, o recarga créditos y establece enabled en true. |
| Cambiar el intervalo | PATCH /v1/schedules/{id} con un cron nuevo; el siguiente inicio se cuenta desde ahora. |
| Pausar | ephemeral schedules pause ID y resume, o enabled en un PATCH. |
POST /v1/runs, el mismo flujo de trabajo y un callback. El receptor es el de la receta de investigar un pago. Entonces renuncias a la protección contra solapamientos y al calendario de Ephemeral, así que reserva las programaciones para el trabajo que no necesites empujar.