Table of Contents

History Views

This page is part of the documentation for Orleans.Lattice 9.9.0 (release line 9.9), built 2026-10-04. It is also published as markdown, with every table and list, at README.md, and llms.txt lists every page.

What it shows

An opt-in durable per-key history view: an append-only materialised view that records every revision of every key in a source tree, surviving source WAL garbage collection. This sample enables a runtime history view over an orders tree with FullValue retention, writes five successive values to one key, then reads the timeline back with ScanEntryHistoryAsync. Because a history view is enabled, Source is View (not the best-effort WalWindow fallback), Truncated is always false, and - thanks to FullValue retention - each revision carries its value bytes so the historical values print verbatim, even though a plain GetAsync only ever returns the latest one.

Run it

dotnet run --project samples/HistoryViews

Expected output

Silo starting... ready.

History retention for 'orders': mode=FullValue, window=00:00:00
Durable history view 'orders-history' created (forward-only).

Writing 5 successive revisions to key 'order-42':
  set 'order-42' = 'placed'
  set 'order-42' = 'paid'
  set 'order-42' = 'packed'
  set 'order-42' = 'shipped'
  set 'order-42' = 'delivered'

View apply lag after catch-up: 0

Plain GetAsync('order-42') -> 'delivered' (latest only)

ScanEntryHistoryAsync('order-42') - the durable revision timeline:
  #1 hlc=HLC(639186132104706995:0) kind=Set value='placed' (shape=FullValue)
  #2 hlc=HLC(639186132104937326:0) kind=Set value='paid' (shape=FullValue)
  #3 hlc=HLC(639186132104984736:0) kind=Set value='packed' (shape=FullValue)
  #4 hlc=HLC(639186132104995873:0) kind=Set value='shipped' (shape=FullValue)
  #5 hlc=HLC(639186132105004997:0) kind=Set value='delivered' (shape=FullValue)

Source=View (View = durable history view, survives WAL GC)
Truncated=False (always false on the View path - bounded only by retention age)
Total durable revisions read: 5

(Clock values differ per run. window=00:00:00 means no age bound - revisions never expire. The program's (forward-only) label simplifies: this run writes nothing to orders before the view exists, but a view created over existing data can also record earlier revisions - see When not to use.)

When to use

  • You need a complete, retention-bounded audit timeline that outlives WAL garbage collection.
  • You want point-in-time values served straight from the history (FullValue or Hybrid retention), or compact change detection (MetadataOnly).

When not to use

  • For quick, ad-hoc inspection with zero setup - the best-effort WAL-window fallback (see ChangeHistory) needs no view and no extra storage.
  • To reconstruct revisions from before the view existed. A new view starts from what the source still holds: while nothing has been trimmed from the source write-ahead log, its first drain replays the log from the beginning and keeps the original clocks, but once garbage collection has trimmed the log's start it seeds only one revision per live key, from current state. It takes the same current-state seed, trimmed or not, when the source tree already resolves to a different physical tree (after a resize or a restore, for example). Enable the view before the writes you need to keep, as this sample does.

Feature doc