Agendamiento: every, after y timeout
En esta página
Zolo tiene tres construcciones de agendamiento integradas en el lenguaje. Todas
son palabras reservadas — no uses every, after ni timeout como nombres
de variable; prefiere intervalo, agendado, plazo o limite en su lugar.
every — bucle periódico
every <dur> { ... } repite el cuerpo en el intervalo indicado. Es un bucle
infinito por diseño: termínalo con break cuando se alcance la condición de
salida.
Un contador con break tras 3 iteraciones; una suma acumulada que se detiene al
alcanzar el total deseado.
// Feature: periodic loop with `every <dur> { ... }`
// Syntax: `every <duration> { body }` — repeats the body at the given
// interval. It is a keyword (not a variable name).
// When to use: health-checks, polling, animation, metrics, any
// task that needs to run repeatedly on a fixed interval.
var tick = 0
// Runs 3 times (short interval for the demo) and exits with `break`.
every 50ms {
tick = tick + 1
print("tick #{tick}")
if tick >= 3 {
break
}
}
print("done")
// expected:
// tick #1
// tick #2
// tick #3
// done
// Another example: summing until a total is reached.
var total = 0
every 25ms {
total = total + 10
if total >= 30 {
break
}
}
print("total = {total}")
// expected: total = 30
after — disparo único
after <dur> { ... } agenda la ejecución del bloque una sola vez, tras el
retraso. Es fire-and-forget: no bloquea el flujo principal. Usa sleep
después para mantener el programa vivo hasta que el callback se dispare.
Tres after coexistiendo; el orden de disparo lo determina el scheduler.
// Feature: schedule one execution with `after <dur> { ... }`
// Syntax: `after <duration> { body }` — fire-and-forget; the block
// runs **once** after the delay. It is a keyword.
// When to use: one-shot callbacks, timers, expirations, single
// reminders. Unlike `every`, it does not repeat.
print("scheduling...")
// Block runs 50ms later — does not block the main flow here.
after 50ms {
print("fired after 50ms!")
}
// Multiple `after` may coexist.
after 100ms {
print("fired after 100ms!")
}
after 25ms {
print("this one was first")
}
print("scheduled, waiting...")
// Keep the program alive long enough to see the firings.
sleep 200ms
print("end")
// expected (approximate order — depends on the scheduler):
// scheduling...
// scheduled, waiting...
// this one was first
// fired after 50ms!
// fired after 100ms!
// end
timeout — cancelación por plazo
timeout <dur> { ... } devuelve un objeto { ok, value, error }. Si el bloque
concluye dentro del plazo, ok es true y value contiene el retorno. Si
expira, ok es false y error es "timeout". Como el scheduler es
cooperativo, la cancelación solo ocurre en puntos de yield (sleep, IO, etc.).
Camino feliz con retorno dentro del plazo; nota sobre el comportamiento cooperativo y alternativa de nombre para la variable de plazo.
// Feature: cancel work that takes too long with `timeout`
// Syntax: `timeout <dur> { body }` — returns a `Result`-like
// (`{ ok, value, error }`) with `ok = true` if it completed, or
// `ok = false, error = "timeout"` if it expired.
// When to use: network calls, uncertain IO, tasks that need a
// fail-safe. Cooperative: only fires at a yield point.
// Happy path: body finishes within the deadline.
let result_ok = timeout 100ms {
return 42
}
if result_ok.ok {
print("ok: {result_ok.value}")
} else {
print("err: {result_ok.error}")
}
// expected: ok: 42
// Timeout case: body takes longer than the limit and is interrupted.
// Note: cooperative — the body must yield (e.g. via `sleep`) for
// the deadline to fire. If it never yields, the body runs to
// completion and `ok = true`.
// SKIP: sleep inside `timeout { ... }` raises a YieldError in the
// current runtime; the failure case is therefore commented out.
//
// let result_slow = timeout 30ms {
// sleep 200ms
// return "too late"
// }
// if result_slow.ok {
// print("ok: {result_slow.value}")
// } else {
// print("err: {result_slow.error}")
// }
//
// expected: err: timeout
// IMPORTANT: `timeout` is a reserved keyword — you cannot use it
// as a variable name. Use `deadline`, `limit`, `dur`, etc. instead.
let limit = 5000
print("using '{limit}' instead of 'timeout' as the name")
Desafío
Combina every 100ms con un after 500ms que establezca un flag de parada. El
every debe verificar el flag y llamar a break cuando sea verdadero.
Consulta también