Skip to content

4. Make it live

We keep saying the catalog “stays live.” This chapter makes that concrete — and shows that you already built it, without writing a line of real-time plumbing.

Go back to every query we’ve written: each observes storage rather than returning a one-shot list. The C# ISubject<…>, JVM Flow<List<…>>, and TypeScript ObservableSource<…> all expose streams. Arc serves each as an observable query; on the React side, the generated .use() hook subscribes to it. So the data flow isn’t “fetch once and render” — it’s a standing subscription:

writes

notification

AddBook

Books

BooksForAuthor.use()

React re-renders

When a command writes and the configured observation source notifies, the observable query publishes updated data to subscribed React components, which re-render. Open the app in two browser tabs, add a book in one, and watch it appear in the other — you wrote none of that plumbing. It falls out of returning Observe() and calling .use().

Continue from chapter 3. Open two browser tabs connected to the same backend process. Subscribe to the same author’s catalog in both; add a book in one and verify the other updates without reload. This tests the tutorial’s live path, including SQLite. It does not prove cross-process observation.

External writes are a separate test: MongoDB change streams can report them when configured; SQLite cannot. For EF’s other providers, configure their database notification mechanism before testing a write from a second process. No notification source means an observable endpoint can stay connected without fresh data.

The following are alternative MongoDB method fragments in Author, using the tutorial imports. Replace the method rather than adding a second method with the same signature.

Nothing special — just the return type. A one-shot query returns the data:

public static IEnumerable<Author> AllAuthors(IMongoCollection<Author> authors) =>
authors.Find(_ => true).ToList();

View C# snippet source on GitHub

Make it return a stream instead — an ISubject<…> on C#, a Flow<List<…>> on the JVM, or an ObservableSource<Author[]> on TypeScript — and the method becomes a live subscription. The proxy and the React .use() adapt automatically, and the frontend code is identical for every backend:

public static ISubject<IEnumerable<Author>> AllAuthors(IMongoCollection<Author> authors) =>
authors.Observe();

View C# snippet source on GitHub

That’s the whole switch between “load once” and “stay live.” You choose per query: a rarely-changing lookup can be a plain list; a screen the librarian watches should observe.

  • A clear picture of why your screens update themselves — observable queries are standing subscriptions, database to browser.
  • The method-level difference between a one-shot query and a live one — the return type and observation call, with a configured notification source underneath.

The catalog is live. There’s just one thing left before it’s a real back office: right now anyone can register authors and add books. Let’s decide who’s allowed. Lock it down →