14. Picking a Sample — Start with the Example Closest to Your Problem¶
Guide Home | Previous: 13. Key Type Usage Index | Next: 15. E2E Testing — Verifying the Whole System with a Client
View in another language — C#/.NET · C++ · Java · Kotlin · Node/TypeScript
This chapter has no spec document that owns a contract. It's guidance for choosing which sample to look at. Each sample's language-neutral scenario, message contract, and verification criteria are defined by the common sample document. This document lays out which sample is the best place to start and how to run it.
The samples are split so each one owns a different bundle of features. You don't need to read all of them — it's faster to pick the one closest to what you're building and follow its registration code and handlers.
If you don't know where to start, look at Bingo. It's where the most framework features show up, and its architecture mirrors that of a typical online game server.
1. Choosing by What You're Building¶
| System you're building | Sample | What this sample covers |
|---|---|---|
| A real-time head-to-head game server | TicTacToe | The smallest configuration, with auto-connect and auto-registration stripped away |
| A full online game server — where the most framework features show up | Bingo | A conventional game server split into a connection gateway, auth/matchmaking, and room servers |
| A live chat support system | SupportChat | An actor/routing setup where one agent handles several conversations at once |
| A dispatch system | DeliveryDispatch | Create a request → pick a fulfiller → reassign on no response → deliver to the party involved |
| An order-processing system | ShoppingMall | Lossless event sourcing written as sequential code, with no orchestration layer |
| A quest/mission progression system | GameQuest | Owner processing that accepts possible data loss in exchange for real-time responsiveness |
| A zone-sharded MMORPG with ops control | ZoneWorld — a common target sample in every language | Which surface to pick when doing something across multiple nodes |
To pick by feature instead, look at the 01. Overview's introduction order first.
Two pairs are built to contrast with each other, and looking at them together makes the decision criteria clear.
- TicTacToe ↔ Bingo — the same real-time game shown once with manual connect/manual registration, and once with auto-connect/auto-registration; once with Play owning the session directly, and once with a separate gateway. Because C++ has no handler scanner, it registers handlers directly in both samples, but follows the same connection rule.
- ShoppingMall ↔ GameQuest — the same owner Spot/event sourcing shown once for a domain that needs zero loss, and once for a domain that tolerates loss and corrects for it.
2. TicTacToe — Building a Real-Time Head-to-Head Game Server¶
The smallest real-time game server configuration, handling a two-player match with 2
Apis and 2 Plays. It's also the only sample that writes endpoints directly instead of
handing peer connections to the location store. Even so, the Location Store still resolves
which node currently owns a room or actor — what's manual is the connection between nodes,
not object location lookup. In managed languages, it's also the only sample that registers
handlers directly in configuration code without scanning. C++ registers handlers directly in
every sample, but uses manual connections only in TicTacToe.
With no separate Session server, each Play owns the stream session, actor, Entry Spot, and
room Spot together. The client connects directly to a Play from the list of Play endpoints
it got from Api. When the win count reaches 100, the room Spot publishes a milestone by
Logical Multicast, and an observer handler registered on another Play server's Entry Spot
receives it and pushes it to spectating clients.
- Paired chapters: 05-channel-messaging (ClientServer channel), 06-spot (creating a User Spot), 09-stream
- Scenario: TicTacToe · payload JSON
- The 02. Getting Started follows this sample. If this is your first read, start here.
3. Bingo — Building an Online Game Server¶
If you pick only one, pick this sample. Everything an online game server needs — authentication, matchmaking, game progress, real-time push — is all in here, and it's where the most framework features show up. Three kinds of Spot, actor-to-session binding, remote Spot join, Spot timers, Logical Multicast, and location-store auto-connect all appear in sequence within one flow.
At the same time, this shape isn't specific to Bingo — it's exactly a typical online game's server configuration. The client connects to only one connection server; authentication and matchmaking are handled by a separate server; and game progress is processed by the server that owns the room. Even building a different genre, the role split and connection shape rarely stray far from this, so it's a good starting point for a new service.
Session owns the client connection and actor binding; Play owns the player actor and the
room User Spot; Api handles auth and matching requests; Matchmaking owns a Matchmaker
Instance Spot per level. The client keeps only one connection, to Session, and the
shared Location Store resolves server-to-server connections. Session, Api, and Play
each run 2 instances, to confirm scale-out still holds even in a gateway shape.
This sample uniquely shows how the Matchmaker Instance Spot atomically decides waiting-room reservations against Redis and how, even when the player actor and the room Spot are on different Play servers, the framework finds the current owner and executes a remote Spot join. After that, the room Spot draws a number on a timer, pushes it to the bound session, and if a rare reward comes up, delivers it to spectators on other Play servers via Logical Multicast.
This is the only sample where the payload is Protobuf. Because it's a gateway-shaped game with many roles and contracts, the schema is used as the anchor so each language's sample keeps the same field and wire names.
- Paired chapters: 06-spot (all three Spot kinds appear), 07-actor-spot, 08-actor-session, 10-location
- Scenario: Bingo · payload Protobuf
- The registration-code examples in chapters 06 and 07 come from this sample.
4. SupportChat — Building a Live Chat Support System¶
A system where a customer requests support, an agent is assigned, and they chat in real time. One conversation maps to a conversation Spot, which owns the participants, message order, typing state, and closed state.
The technical difficulty in this domain comes from one agent handling several customers at the same time. A customer has only one conversation, so their own actor is directly that conversation's participant. An agent can't work that way — in the framework, one actor belongs to only one Spot at a time, and joining a new Spot means leaving the previous one. One agent actor can't be inside three conversations at once.
So the agent side splits its actor into two kinds.
| actor | Belongs to | Responsibility |
|---|---|---|
| roster actor | Entry Spot | Owns the agent's identity and availability, and receives assignment notifications. Created once at authentication |
| conversation actor | Each conversation Spot | The participant in one conversation. One is created for each conversation the agent joins |
One connection, but several actors. The agent client keeps only one stream connection and binds both the roster actor and each per-conversation actor to that session.
Inbound messages are distinguished by carrying ConversationId in the stream message's
metadata. The Session server reads only the metadata to pick the target actor
and never parses the payload. This keeps the connection server decoupled from the
support domain's schema. On the outbound side, pushes from each conversation Spot converge
onto the same single connection through the session bound to that actor.
Assignment is capacity-based. If no agent has capacity left, the request stays pending rather than erroring; once an agent's capacity fills up, they drop out of the assignment list and rejoin once a conversation closes. On reconnect, a new session binds to the same actor, allowing the conversation state to continue unchanged. If no message arrives for a while, a Spot timer starts the conversation-closing flow.
This shape isn't specific to support. Any system where one user participates in several rooms/tasks at once has the same architecture.
- Paired chapters: 08-actor-session, 06-spot (timer), 09-stream
- Scenario: SupportChat · payload JSON
5. DeliveryDispatch — Building a Dispatch System¶
Create a delivery, offer it to a courier, reassign it if there's no response within a set time, and deliver status updates to the customer. This sample's point isn't delivery business rules — it shows how the common requirements to create a request, pick a fulfiller, deliver to a specific user's connection, and retry on no response map to framework features. Ride-hailing, field dispatch, and on-site service requests use the same architecture.
The external boundary still uses standard web technology. The customer creates a delivery over HTTP and receives status over a stream. What changes is what's inside — instead of keeping a session map or socket registry directly, the session bound to the customer actor stands in for it, and courier selection and reassignment are owned by the dispatch worker and the courier actor route. The client scenario verifies both the normal-dispatch and the timeout-reassignment flows.
- Paired chapters: 05-channel-messaging, 07-actor-spot, 09-stream
- Scenario: DeliveryDispatch · payload JSON
6. ShoppingMall — Building an Order-Processing System¶
One order is owned by an OrderWorkflow owner Spot, which reserves inventory → approves
payment → confirms the order, and compensates on failure. CommerceApi terminates the
outer HTTP boundary but never changes order state directly.
The payoff of an owner Spot in this sample isn't throughput. The key point is writing a multi-step process that's safe under retry and interruption as sequential code, with no separate orchestration layer — no saga orchestrator, no coordination state, no scheduler, no outbox. What a web setup usually assembles from outside infrastructure — "save the progress point, coordinate the next step, resume a stalled task" — collapses into a single event stream. An idempotency key handles duplicate clicks, an expected version handles periods when the previous owner is still present, and an explicit resume command handles stalled orders. If the read model breaks, it can be rebuilt by replaying the events.
- Paired chapters: 06-spot, 12-operations
- Scenario: ShoppingMall · payload JSON
- Event sourcing itself isn't a framework feature — it's a shape the application builds on top of a Spot.
7. GameQuest — Building a Quest Progression System¶
This sample gathers per-player gameplay events and has the server determine quest
progress and completion. Letting the client say "I finished the quest, give me the reward"
invites cheating, so all progress and reward decisions happen inside the PlayerId owner Spot. One
owner processes the same player's events in order, and progress is pushed to the connection
through a projection.
Placed next to ShoppingMall, the decision criteria become clear. Game progress has resynchronization as a safety valve, so it accepts possible data loss in exchange for real-time responsiveness. That's why it doesn't have zero-loss mechanisms like blocking the previous owner or requiring an explicit resume — a gap is absorbed by snapshot-based correction instead. Anything that genuinely needs zero loss, like an actual currency payout, is split into a separate tier.
- Paired chapters: 06-spot, 08-actor-session
- Scenario: GameQuest · payload JSON
8. ZoneWorld — Building a Zone-Sharded MMORPG and Ops Control¶
ZoneWorld is a common sample implemented by all five framework languages. Each implementation follows this chapter and the common scenario for topology, actor relocation, operations fanout, and browser verification.
The world is divided into zones managed across several ZoneNodes. The Location Store and
the framework determine which node owns each zone. When a player crosses a
boundary, their actor joins the adjacent zone Spot, and if the owner differs, relocation
happens — but the client connection stays intact. A bot actor with no bound session makes
the same boundary crossing on a Spot timer.
This sample's teaching point is that "doing something across multiple nodes" calls for a different surface depending on the situation.
| What you're trying to do | Surface used |
|---|---|
| See which nodes are registered/connected | runtime event — a change notification, not a request; a terminated node has no target to request from |
| Announce to every node | classic fanout — the publisher never holds a node list |
| Switch a specific node into maintenance mode | desired state + fanout — each node applies only the state associated with its own NodeId |
| Send to every player in one zone | zone Spot → its actors → each one's bound session |
| Send to one specific player | that actor → its own bound session |
State near a boundary is delivered by Logical Multicast on a per-adjacent-zone topic. If one topic were shared by several zones, unrelated players would receive it too, so the topic name carries both the sending and receiving zone. It's the only sample with a browser UI, so you can watch boundary crossings and maintenance-mode changes in the browser.
- Paired chapters: 07-actor-spot (relocation), 11. Monitoring, 12-operations
- Scenario: ZoneWorld · payload JSON
- The server and runner are provided in all five languages and share the business behavior and verification criteria. The .NET and Node.js browser smoke tests use the same TypeScript client.
9. Running It¶
One runner per sample directory brings up several servers together with a client scenario,
and runs verification too. For a sample that needs a location store, the runner brings up
its own Redis container and cleans it up when done, so all you need is docker.
# Run one sample
framework/languages/dotnet/samples/Bingo/run_sample.sh
# Run several in sequence (omit the arguments to run all)
framework/languages/dotnet/samples/run_samples.sh TicTacToe Bingo
The common sample target includes ZoneWorld and its browser UI. Every language's
run_samples.sh runs all seven server samples, including ZoneWorld.
To run only ZoneWorld, invoke ZoneWorld/run_sample.sh from that language's sample root.
10. Related Documents¶
- Each sample's language-neutral scenario and verification criteria: Common sample
- Per-language sample directory layout: the
READMEat each language's sample root - Per-feature usage: 05-channel-messaging through 12-operations