Skip to content

Commit

Permalink
Adding slog (#4)
Browse files Browse the repository at this point in the history
* Adding slog

* Disable golangci-lint

Day 1 issues, not yet supporting 1.21: golangci/golangci-lint#3922
  • Loading branch information
renevo authored Aug 9, 2023
1 parent e15c37c commit 95e3015
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 22 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
ci:
strategy:
matrix:
go-version: [1.20.x]
go-version: [1.21.x]
platform: [ubuntu-latest]

runs-on: ${{ matrix.platform }}
Expand All @@ -29,7 +29,7 @@ jobs:
- name: Tester
run: go test -v -cover ./...

- name: Linter
uses: golangci/golangci-lint-action@v3
with:
version: latest
#- name: Linter
# uses: golangci/golangci-lint-action@v3
# with:
# version: latest
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ This is under heavy development, and should not be used before a 1.0.0 release,

The Actor Model is a computational model used to build highly concurrent and distributed systems. It was introduced by Carl Hewitt in 1973 as a way to handle complex systems in a more scalable and fault-tolerant manner.

In the Actor Model, the basic building block is an actor, called receiver in Hollywood, which is an independent unit of computation that communicates with other actors by exchanging messages. Each actor has its own state and behavior, and can only communicate with other actors by sending messages. This message-passing paradigm allows for a highly decentralized and fault-tolerant system, as actors can continue to operate independently even if other actors fail or become unavailable.
In the Actor Model, the basic building block is an actor, called receiver in this package, which is an independent unit of computation that communicates with other actors by exchanging messages. Each actor has its own state and behavior, and can only communicate with other actors by sending messages. This message-passing paradigm allows for a highly decentralized and fault-tolerant system, as actors can continue to operate independently even if other actors fail or become unavailable.

Actors can be organized into hierarchies, with higher-level actors supervising and coordinating lower-level actors. This allows for the creation of complex systems that can handle failures and errors in a graceful and predictable way.

Expand Down
12 changes: 11 additions & 1 deletion engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package actor

import (
"context"
"log/slog"
"reflect"
"strings"
"sync"
)
Expand Down Expand Up @@ -43,7 +45,15 @@ func NewEngine(defaultOpts ...Option) *Engine {
e.pid.Address = LocalAddress

e.deadletter = e.SpawnFunc(func(ctx *Context) {
// TODO: Deadletter stuff
switch ctx.Message().(type) {
case Initialized, Started, Stopped:
// if we have anything, add it here

default:
// TODO: publish deadletter to Events once we have them
slog.Warn("Deadletter", "to", ctx.sender, "from", ctx.sender, "msg", reflect.TypeOf(ctx.Message()))
}

}, "engine", WithTags("deadletter"), WithInboxSize(defaultInboxSize*4))
e.deadletter.Address = LocalAddress

Expand Down
10 changes: 5 additions & 5 deletions engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package actor_test

import (
"context"
"fmt"
"log/slog"
"strconv"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -55,15 +55,15 @@ func TestProcessInitStartOrder(t *testing.T) {
pid := engine.SpawnFunc(func(c *actor.Context) {
switch c.Message().(type) {
case actor.Initialized:
fmt.Println("init")
slog.Info("init")
wg.Add(1)
init = true
case actor.Started:
fmt.Println("start")
slog.Info("start")
require.True(t, init)
started = true
case int:
fmt.Println("msg")
slog.Info("msg")
require.True(t, started)
wg.Done()
}
Expand All @@ -82,7 +82,7 @@ func TestSendMsgRaceCon(t *testing.T) {
pid := engine.SpawnFunc(func(c *actor.Context) {
msg := c.Message()
if msg == nil {
fmt.Println("should never happen")
slog.Error("should never happen")
}
}, "test")

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/renevo/actor

go 1.20
go 1.21

require github.com/stretchr/testify v1.8.4

Expand Down
10 changes: 5 additions & 5 deletions processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package actor

import (
"context"
"fmt"
"os"
"log/slog"
"reflect"
"sync"
"time"
)
Expand Down Expand Up @@ -61,7 +61,7 @@ func (p *processor) Send(ctx context.Context, _ PID, msg any, from PID) {
}

if err := p.inbox.Deliver(envelope); err != nil {
fmt.Fprintf(os.Stderr, "failed to deliver message to %s; from: %s; type: %T: %v\n", p.pid, from, msg, err)
slog.Error("Failed to deliver message to inbox.", "inbox", p.pid, "from", from, "msg", reflect.TypeOf(msg), "err", err)
}
}

Expand Down Expand Up @@ -158,12 +158,12 @@ func (p *processor) tryRestart(v any) {
p.restarts++

if p.restarts >= p.options.MaxRestarts {
fmt.Fprintf(os.Stderr, "Process max restarts exceeded, shutting down: pid: %s; restarts: %d\n", p.pid, p.restarts)
slog.Error("Actor process max restarts exceeded, shutting down.", "pid", p.pid, "restarts", p.restarts)
p.cleanup(nil)
return
}

fmt.Fprintf(os.Stderr, "Process actor restarting: count: %d; maxRestarts: %d; pid: %s; reason: %v\n", p.restarts, p.options.MaxRestarts, p.pid, v)
slog.Warn("Actor process restarting.", "pid", p.pid, "count", p.restarts, "maxRestarts", p.options.MaxRestarts, "err", v)
time.Sleep(p.options.RestartDelay)
p.Start()
}
10 changes: 7 additions & 3 deletions registry.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package actor

import "sync"
import (
"log/slog"
"reflect"
"sync"
)

type registry struct {
mu sync.RWMutex
Expand All @@ -24,8 +28,8 @@ func (r *registry) add(proc Processor) {
defer r.mu.Unlock()

id := proc.PID().ID
if _, ok := r.lookup[id]; ok {
// TODO: handle duplicates
if existing, ok := r.lookup[id]; ok {
slog.Warn("Attempt to register duplicate process.", "pid", proc.PID(), "existing", reflect.TypeOf(existing), "conflict", reflect.TypeOf(proc))
return
}

Expand Down
4 changes: 3 additions & 1 deletion request.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package actor

import (
"context"
"log/slog"
"math/rand"
"reflect"
"strconv"
"sync"
"time"
Expand Down Expand Up @@ -72,7 +74,7 @@ func (c *Context) Request(to PID, msg any, timeout time.Duration) (any, error) {

func (c *Context) Respond(msg any) {
if c.sender.IsZero() {
// TODO: Log about responding to no one
slog.Warn("Call to Respond with no sender in context.", "pid", c.pid, "msg", reflect.TypeOf(msg))
return
}

Expand Down

0 comments on commit 95e3015

Please sign in to comment.