A refresh policy for chain-derived data -- the missing piece between
Block.watchBlockNumber and your RemoteCalls.
Chain data goes stale exactly once per block, so refetch cadence should be expressed in blocks, not milliseconds:
type alias Model =
{ ticker : BlockRefresh.Ticker
, balance : RemoteCall String
}
-- init
{ ticker = BlockRefresh.init (EveryNBlocks 5), ... }
-- on each { tag = "blockNumber" } port message:
let
( ticker, refetch ) =
BlockRefresh.onBlock number model.ticker
in
if refetch then
( { model | ticker = BlockRefresh.markRefreshed number ticker
, balance = RemoteCall.request "bal-..." model.balance }
, web3Cmd (Balance.encode ...)
)
else
( { model | ticker = ticker }, Cmd.none )That worked example IS the balance watcher: balances re-read on-cadence,
driven by chain time. Any RemoteCall slots in the same way.
Tracks the policy and the block height of the last refresh. Opaque.
Change cadence, keeping the last-refreshed watermark.
Feed a new block number in; the Bool says "fire your refetch now".
The first observed block always fires (except under Manual) -- data that
has never been fetched is infinitely stale.
Record that the refetch was actually fired at this height. Separate from
onBlock so a refetch you decided to skip (e.g. one already in
flight) doesn't advance the watermark.
EveryBlock-- refetch on every new block.EveryNBlocks n-- refetch when at leastnblocks have passed since the last refresh.Manual-- never fire from block signals (the app refetches explicitly).