22 · Expressões Temporais
Agendamento: every, after e timeout
Loop periódico com `every`, disparo único com `after`, e cancelamento por prazo com `timeout`.
Nesta página
Zolo tem três construções de agendamento integradas à linguagem. Todas são
palavras reservadas — não use every, after ou timeout como nomes de
variável; prefira intervalo, agendado, prazo ou limite.
every — loop periódico
every <dur> { ... } repete o corpo no intervalo indicado. É um laço infinito
por design: encerre-o com break quando a condição de saída for atingida.
Contador com break após 3 iterações; soma acumulada que para ao atingir o
total desejado.
// 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 a execução do bloco uma única vez, após o atraso.
É fire-and-forget: não bloqueia o fluxo principal. Use sleep depois para
manter o programa vivo até o callback disparar.
Três after coexistindo; ordem de disparo determinada pelo 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 — prazo de cancelamento
timeout <dur> { ... } retorna um objeto { ok, value, error }. Se o bloco
concluir dentro do prazo, ok é true e value contém o retorno. Se expirar,
ok é false e error é "timeout". Como o scheduler é cooperativo, o
cancelamento só ocorre em pontos de yield (sleep, IO, etc.).
Caminho feliz com retorno dentro do prazo; nota sobre o comportamento cooperativo e alternativa de nome para a variável de prazo.
// Feature: cancel work that takes too long with `timeout`
// Syntax: `timeout <dur> { body }` returns `Result<T, TimeoutError>`.
// 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
}
match result_ok {
Result::Ok(value) => print("ok: {value}"),
Result::Err(error) => print("err: {error.message}"),
}
// expected: ok: 42
// 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")
// Timeout case: body takes longer than the limit and is interrupted.
// Note: cooperative — the deadline is checked each time the body
// yields (e.g. via `sleep`), so slow work needs checkpoints: a body
// that never yields, or yields once and then finishes, runs to
// completion and returns Ok. A yielding body also needs a task to
// yield to, so run the block inside `spawn` (the top-level main
// thread cannot yield); the task prints after the main chunk ends.
spawn {
let result_slow = timeout 30ms {
for _ in 0..10 {
sleep 20ms // each sleep is a checkpoint where the deadline can fire
}
return "too late"
}
match result_slow {
Result::Ok(value) => print("ok: {value}"),
Result::Err(error) => print("err: {error.message}"),
}
}
// expected: err: timeout
Desafio
Combine every 100ms com um after 500ms que seta uma flag de parada. O
every deve verificar a flag e chamar break quando ela for verdadeira.
Veja também