Skip to content

Commit

Permalink
WIP: Redis persistance example (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
anthdm authored Nov 17, 2023
1 parent 51023ac commit 244f0bb
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 0 deletions.
153 changes: 153 additions & 0 deletions examples/persistance/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package main

import (
"context"
"encoding/json"
"fmt"
"log"
"sync"
"time"

"github.com/anthdm/hollywood/actor"
"github.com/redis/go-redis/v9"
)

type Storer interface {
Store(key string, data []byte) error
Load(key string) ([]byte, error)
}

func WithPersistance(store Storer) func(actor.ReceiveFunc) actor.ReceiveFunc {
return func(next actor.ReceiveFunc) actor.ReceiveFunc {
return func(c *actor.Context) {
switch c.Message().(type) {
case actor.Initialized:
p, ok := c.Receiver().(Persister)
if !ok {
next(c)
return
}
b, err := store.Load(c.PID().String())
if err != nil {
fmt.Println(err)
next(c)
return
}
var data map[string]any
if err := json.Unmarshal(b, &data); err != nil {
log.Fatal(err)
}
if err := p.LoadState(data); err != nil {
fmt.Println("load state error:", err)
next(c)
}
case actor.Stopped:
if p, ok := c.Receiver().(Persister); ok {
s, err := p.State()
if err != nil {
fmt.Println("could not get state", err)
next(c)
return
}
if err := store.Store(c.PID().String(), s); err != nil {
fmt.Println("failed to store the state", err)
next(c)
return
}
}
}
next(c)
}
}
}

type Persister interface {
State() ([]byte, error)
LoadState(map[string]any) error
}

type State struct {
Health int `json:"health"`
Username string `json:"username"`
}

type PlayerState struct {
Health int
Username string
}

type TakeDamage struct {
Amount int
}

func (p *PlayerState) Receive(c *actor.Context) {
switch msg := c.Message().(type) {
case actor.Started:
case actor.Stopped:
case TakeDamage:
p.Health -= msg.Amount
fmt.Println("took damage, health ", p.Health)
}
}

func newPlayerState(health int, username string) actor.Producer {
return func() actor.Receiver {
return &PlayerState{
Health: health,
Username: username,
}
}
}

func (p *PlayerState) LoadState(data map[string]any) error {
fmt.Println("player loading state", data)
p.Health = int(data["health"].(float64))
p.Username = data["username"].(string)
return nil
}

func (p *PlayerState) State() ([]byte, error) {
state := State{
Username: p.Username,
Health: p.Health,
}
return json.Marshal(state)
}

type RedisStore struct {
client *redis.Client
}

func newRedisStore(c *redis.Client) *RedisStore {
return &RedisStore{
client: c,
}
}

func (r *RedisStore) Store(key string, state []byte) error {
return r.client.Set(context.TODO(), key, state, 0).Err()
}

func (r *RedisStore) Load(key string) ([]byte, error) {
val, err := r.client.Get(context.TODO(), key).Result()
return []byte(val), err
}

func main() {
var (
e = actor.NewEngine()
redisClient = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
store = newRedisStore(redisClient)
pid = e.Spawn(newPlayerState(100, "James"), "playerState", actor.WithMiddleware(WithPersistance(store)))
)
time.Sleep(time.Second * 1)
e.Send(pid, TakeDamage{Amount: 9})
time.Sleep(time.Second * 1)
wg := &sync.WaitGroup{}
e.Poison(pid, wg)
wg.Wait()
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ require (
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/prometheus/client_golang v1.15.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/redis/go-redis/v9 v9.0.4 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)

Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
Expand Down Expand Up @@ -37,6 +39,8 @@ github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
github.com/redis/go-redis/v9 v9.0.4 h1:FC82T+CHJ/Q/PdyLW++GeCO+Ol59Y4T7R4jbgjvktgc=
github.com/redis/go-redis/v9 v9.0.4/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
Expand Down

0 comments on commit 244f0bb

Please sign in to comment.