Hooks del Ciclo de Reload
En esta página
El pipeline completo de un swap sigue este orden:
dispose → ejecuta el nuevo chunk → fusiona → accept → __on_reload.
Cada etapa es opcional y los errores en cualquier hook se registran pero nunca
abortan el swap.
Notificación post-swap: __on_reload
La forma más sencilla de reaccionar a un reload es definir
pub fn __on_reload(name: str) en el módulo. La función se llama al final,
después de toda la fusión, y es útil para logs estructurados, telemetría o
invalidación de cachés secundarios.
En el ejemplo siguiente, plugin.zolo cuenta cuántas veces ha sido recargado
e imprime ese contador en cada swap:
Edita la fórmula en process; el hook cuenta y muestra el 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)")
}
Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo 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)}")
}
}
Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo localmente.
Migración explícita: #[hot_dispose] y #[hot_accept]
Cuando la preservación automática por tipo no es suficiente — por ejemplo, al
cambiar el schema del estado — los atributos @hot_dispose y @hot_accept
otorgan control total.
@hot_dispose se llama antes de que el nuevo chunk se ejecute y debe
retornar un snapshot de todo lo que necesita sobrevivir. @hot_accept se llama
después de la fusión y recibe ese snapshot, pudiendo migrar campos o
reconstruir estructuras derivadas.
Cambia el campo version de 2 a 3 y observa la migración aplicándose.
// 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}")
}
}
Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo 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()
}
}
Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo localmente.
Desafío
En el módulo cache.zolo, agrega un campo created_at: str = "unknown" al
snapshot dentro de @hot_dispose y haz que @hot_accept lo registre en el
print. Confirma que el valor aparece correctamente incluso tras múltiples reloads.
Consulta también