Start the environment
What you do
Copy the example environment file and start every service with Docker Compose. Compose waits for the health checks, so the command returns only when Redpanda, Console, Redis, Postgres and Redpanda Connect are ready.
cp .env.example .env
docker compose up -d --wait
If you prefer to create the topics by hand, these commands set the same partition counts and retention the compose file applies. The lines are long; on solution pages they scroll sideways instead of wrapping.
rpk topic create game.player-events --partitions 6 --replicas 1 --topic-config retention.ms=604800000 --topic-config cleanup.policy=delete --topic-config max.message.bytes=1048576
rpk topic create game.match-events --partitions 3 --replicas 1 --topic-config retention.ms=604800000 --topic-config cleanup.policy=delete
rpk topic create game.achievements --partitions 3 --replicas 1 --topic-config retention.ms=2592000000 --topic-config cleanup.policy=compact,delete
rpk topic create game.player-events.dlq --partitions 1 --replicas 1 --topic-config retention.ms=2592000000
The compose file is the one file you edit before starting, and the module file pins the two client libraries.
services:
redpanda:
image: docker.redpanda.com/redpandadata/redpanda:v26.2.2
command:
- redpanda start
- --smp 1
ports:
- 9092:9092
- 8081:8081
healthcheck:
test: ["CMD", "rpk", "cluster", "health"]
interval: 5s
module github.com/redpanda-data/solutions/multiplayer-gaming/leaderboard
go 1.23
require (
github.com/redis/go-redis/v9 v9.6.1
github.com/twmb/franz-go v1.17.1
)
Why
Everything downstream assumes a healthy broker and a reachable Schema Registry. Starting the platform first and verifying it means later failures are about your code, not the environment.
What happens inside
Redpanda starts as a single broker with the Kafka API on 9092, the Schema Registry on 8081 and the HTTP Proxy on 8082. Console connects to all three and turns on Protobuf decoding for the game.* topics.
The leaderboard consumer
The full service is short enough to read in one sitting. Long listings fold to a preview; use the button under the block to expand them.
package main
import (
"context"
"log"
"net/http"
"os"
"github.com/redis/go-redis/v9"
"github.com/twmb/franz-go/pkg/kgo"
)
func main() {
ctx := context.Background()
brokers := os.Getenv("REDPANDA_BROKERS")
rdb := redis.NewClient(&redis.Options{Addr: os.Getenv("REDIS_ADDR")})
cl, err := kgo.NewClient(
kgo.SeedBrokers(brokers),
kgo.ConsumerGroup("leaderboard"),
kgo.ConsumeTopics("game.player-events"),
)
if err != nil {
log.Fatal(err)
}
defer cl.Close()
go serve(rdb)
for {
fetches := cl.PollFetches(ctx)
fetches.EachRecord(func(r *kgo.Record) {
apply(ctx, rdb, r)
})
}
}
func serve(rdb *redis.Client) {
http.HandleFunc("/top", topHandler(rdb))
log.Fatal(http.ListenAndServe(":8080", nil))
}
Complete source: services/leaderboard/main.go
package main
import (
"context"
"log"
"net/http"
"os"
"github.com/redis/go-redis/v9"
"github.com/twmb/franz-go/pkg/kgo"
)
func main() {
ctx := context.Background()
brokers := os.Getenv("REDPANDA_BROKERS")
rdb := redis.NewClient(&redis.Options{Addr: os.Getenv("REDIS_ADDR")})
cl, err := kgo.NewClient(
kgo.SeedBrokers(brokers),
kgo.ConsumerGroup("leaderboard"),
kgo.ConsumeTopics("game.player-events"),
)
if err != nil {
log.Fatal(err)
}
defer cl.Close()
go serve(rdb)
for {
fetches := cl.PollFetches(ctx)
fetches.EachRecord(func(r *kgo.Record) {
apply(ctx, rdb, r)
})
}
}
func serve(rdb *redis.Client) {
http.HandleFunc("/top", topHandler(rdb))
log.Fatal(http.ListenAndServe(":8080", nil))
}
Verify
Check that the cluster is healthy and that Connect is ready to accept a pipeline:
rpk cluster health
curl -s localhost:4195/ready
CLUSTER HEALTH OVERVIEW
=======================
Healthy: true
Unhealthy reasons: []
Controller ID: 0
All nodes: [0]
Nodes down: []
Leaderless partitions (0): []
Under-replicated partitions (0): []
Topics: 6
Partitions: 18
Replicas: 18
Nodes with high disk usage: []
Nodes in maintenance mode: []
Unavailable nodes: []
Cluster UUID: 5c4f7d2e
Last update: 2026-09-13T02:14:07Z
OK
PASS 9/9 checks
Files for this step
-
docker-compose.yml: theredpandaservice is shown above, and the whole file is shown in full on the overview. -
services/leaderboard/go.mod: shown in full above. -
services/leaderboard/main.go: shown in full under Complete source.
Signed-in readers can download each file with the Download control on its code block or from the All build-along files panel.
In production
Do not run Console on the same host as a broker, and put the Schema Registry behind TLS: every producer and consumer in this solution fetches schemas from it. For the full picture, see Production considerations: security.
You finished this solution.
Keep the complete example around for your own projects.
Download the complete example