Hooks de Ciclo de Reload
Nesta página
O pipeline completo de um swap segue a ordem:
dispose → executa o novo chunk → mescla → accept → __on_reload.
Cada etapa é opcional e os erros em qualquer hook são registrados mas nunca
abortam o swap.
Notificação pós-swap: __on_reload
A forma mais simples de reagir a um reload é definir pub fn __on_reload(name: str)
no módulo. A função é chamada por último, depois de toda a mescla, e é útil para
logs estruturados, telemetria ou invalidação de caches secundários.
No exemplo abaixo, plugin.zolo conta quantas vezes foi recarregado e imprime
esse contador a cada swap:
Edite a fórmula em process; o hook conta e exibe o número de reloads.
// Feature: __on_reload(name) hook
// Syntax: `pub fn __on_reload(name: str)` — fired AFTER the swap.
// When to use: structured logging, invalidating secondary caches,
// re-emitting status messages, dev telemetry.
//
// Fired last, after the merge and after __hot_accept.
// Errors here are logged but do not abort the swap.
use std::package
use std::stats
let stats = #{reloads: 0}
pub fn process(input: int) -> int {
// Edit the formula below to see the reload in action.
return input * 2
}
pub fn __on_reload(name: str) {
let live = package.loaded["plugin"]
live.stats.reloads = live.stats.reloads + 1
print(">>> [hook] module '{name}' reloaded ({live.stats.reloads}x)")
}
Requer a CLI/host do Zolo — abra no playground ou rode localmente.
// Feature: custom notification on swap
// Syntax: define `pub fn __on_reload(name)` in the module.
// When to use: integrate with your own logging/telemetry system.
use plugin::{process}
fn main() {
print("ENTER calls process(7). Edit plugin.zolo and watch the hook fire.")
while true {
let line = io::read("*l")
if line is nil || line == "q" {
break
}
print("process(7) = {process(7)}")
}
}
Requer a CLI/host do Zolo — abra no playground ou rode localmente.
Migração explícita: #[hot_dispose] e #[hot_accept]
Quando a preservação automática por tipo não é suficiente — por exemplo, ao
mudar o schema do estado — os atributos @hot_dispose e @hot_accept dão
controle total.
@hot_dispose é chamado antes do novo chunk rodar e deve retornar um
snapshot de tudo que precisa sobreviver. @hot_accept é chamado depois
da mescla e recebe esse snapshot, podendo migrar campos ou reconstruir
estruturas derivadas.
Altere o campo version de 2 para 3 e observe a migração sendo aplicada.
// Feature: explicit migration with __hot_dispose / __hot_accept
// Syntax: `#[hot_dispose] fn ...` and `#[hot_accept] fn ...(prev: any)`.
// When to use: the state's schema changed, OR we want to rebuild
// derived caches, OR the preservation defaults are not sufficient.
//
// Pipeline:
// 1. BEFORE the swap: we call `dispose` -> returns a snapshot.
// 2. New chunk runs (fresh state).
// 3. AFTER the merge: `accept(snapshot)` re-installs / migrates.
use std::package
let entries: any = #{}
let version: int = 2
pub fn add(key: str, value: any) {
let live = package.loaded["cache"]
live.entries[key] = value
}
pub fn dump() {
let live = package.loaded["cache"]
var n = 0
for (_, _) in live.entries {
n = n + 1
}
print("cache: {n} entries, schema v{live.version}")
}
@hot_dispose
fn save_state() -> any {
let live = package.loaded["cache"]
print(">>> dispose: capturing {live.version}")
return #{
entries: live.entries,
version: live.version,
}
}
@hot_accept
fn load_state(prev: any) {
let live = package.loaded["cache"]
if prev == nil {
print(">>> accept: no previous state, skipping")
return
}
if prev.version == live.version {
// same schema: full migration.
live.entries = prev.entries
print(">>> accept: schema v{prev.version} preserved in full")
} else {
// different schema: copy compatible fields.
live.entries = prev.entries ?? #{}
print(">>> accept: migrated v{prev.version} -> v{live.version}")
}
}
Requer a CLI/host do Zolo — abra no playground ou rode localmente.
// Feature: controlled state migration
// Syntax: `#[hot_dispose]` + `#[hot_accept]` in the module.
// When to use: schema migration, explicit rebuild, fine control
// when the preservation defaults are not enough.
use cache::{add, dump}
fn main() {
add("user:1", #{name: "Ana"})
add("user:2", #{name: "Bia"})
dump()
print("ENTER reprints. Edit cache.zolo (e.g. change format or bump version) and save.")
while true {
let line = io::read("*l")
if line is nil || line == "q" {
break
}
dump()
}
}
Requer a CLI/host do Zolo — abra no playground ou rode localmente.
Desafio
No módulo cache.zolo, adicione um campo created_at: str = "unknown" ao
snapshot dentro de @hot_dispose e faça @hot_accept registrá-lo no print.
Confirme que o valor aparece corretamente mesmo após múltiplos reloads.
Veja também