Location¶
Guide Home | Previous: Session and Actor | Next: Monitoring
View in another language — C++ · C#/.NET · Java · Kotlin · Node/TypeScript
What you get from this chapter
You can ask which node a Spot or Actor is on right now, holding nothing but its id. The code comes from the tutorial README in the examples repository; follow its Download, Build, and Run sections to reproduce the results below.
Spot and Actor were called by id alone, and the Framework found which node they were on. The place that holds that record is the Location Store. This chapter covers reading that record from an application; what the Store writes down, and how processes find each other through it, is covered by How Channels Work.
1. Lookup Against Call — a Lookup Changes No State¶
A call makes the target do something. A lookup reads the location without touching the target. Use it to show which server a room is on right now on an operations screen, or to confirm that the record changed after a target was moved.
What comes back is the record as it stands at that moment. It does not confirm that the target actually answers, so when you have to know whether it is alive, send a request rather than a lookup.
2. The Store Requirement on a Node That Looks Up¶
A lookup reads the Store, so the process doing the lookup has to have that Store registered under the same prefix. The registration code is the one in Spot.
A node that runs neither Spots nor Actors and only calls them needs the Location Store alone. The Relocation Store is required only on a node that registered a factory.
3. Asking Where an Id Is¶
A Spot is asked of the spot manager and an Actor of the actor manager. Both take the id alone, and neither names a node to ask.
// find answers from the Location Store alone: it reports where the object is,
// and only while it is ready to receive. Nothing is sent to the object.
@GetMapping("/locations/rooms/{roomId}")
suspend fun findRoom(@PathVariable roomId: String): ResponseEntity<Map<String, String>> {
val room =
rooms.find(roomId).await().orElse(null) ?: return ResponseEntity.notFound().build()
return ResponseEntity.ok(
mapOf("spotId" to room.spotId(), "node" to room.nodeRid().toString())
)
}
@GetMapping("/locations/players/{playerId}")
suspend fun findPlayer(@PathVariable playerId: String): ResponseEntity<Map<String, String>> {
val player =
players.find(playerId).await().orElse(null) ?: return ResponseEntity.notFound().build()
return ResponseEntity.ok(
mapOf("actorId" to player.actorId(), "node" to player.nodeRid().toString())
)
}
What comes back is one reference carrying the id and the node name, and an empty result when nothing is found. A lookup answers only for a target that can receive a message now, so a target still being created, or in the middle of a move, comes back empty as well. One empty result is therefore not a verdict that no such id exists.
4. What You See When You Run It¶
With the tutorial Server and Client running as the README's Run section specifies, send these curl requests to the Client's HTTP surface: each HTTP response appears on curl stdout, and the creation and lookup handler records appear on the Server process's stdout or in server.log.
curl -X POST http://127.0.0.1:5080/rooms \
-H 'Content-Type: application/json' -d '{"title":"lobby"}'
# "5ce8339b-ec20-42d8-a117-a74677ad9af0"
curl http://127.0.0.1:5080/locations/rooms/5ce8339b-ec20-42d8-a117-a74677ad9af0
# {"spotId":"5ce8339b-ec20-42d8-a117-a74677ad9af0","generation":1,"node":"game-server-1"}
curl -X POST http://127.0.0.1:5080/players/p7 \
-H 'Content-Type: application/json' -d '{"nickname":"rookie"}'
# "created"
curl http://127.0.0.1:5080/locations/players/p7
# {"actorId":"p7","generation":1,"node":"game-server-1"}
curl http://127.0.0.1:5080/locations/players/ghost
# 404
Both the room and the player answered game-server-1. The last call asked for an id that was
never created, and the empty result became a 404.
5. The Scope of a Lookup Result — a Node Name Is Not a Call Address¶
The node name a lookup returns is the location at that instant, not a call address. A call gives the id alone, exactly as in Spot and Actor. The Framework reads the same record again on every call, so a target that moves to another node after the lookup is still reached. Take the node name and send through calling a node directly and that following is lost.
There is a place where the reference itself is passed on. A call that closes or destroys takes only the generation that reference points at and leaves a target recreated under the same id untouched.
6. Related Documents¶
- State objects called by id — Spot · Actor
- What the Store writes down — How Channels Work
- Operational queries — Operations and Lifecycle
- A running version of this chapter's code — the tutorial README in the examples repository