From d7187928819ca62d42d9453e07310b22bd2979ce Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Fri, 12 Sep 2025 18:27:24 +0000 Subject: [PATCH] docs(internal/actorify): document package Signed-off-by: Xe Iaso --- internal/actorify/actorify.go | 15 ++++++++++++++- lib/store/actorifiedstore.go | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/internal/actorify/actorify.go b/internal/actorify/actorify.go index d38298b9..907a2cb9 100644 --- a/internal/actorify/actorify.go +++ b/internal/actorify/actorify.go @@ -1,4 +1,5 @@ -// Package actorify lets you transform a parallel operation into a serialized operation via the Actor pattern[1]. +// Package actorify lets you transform a parallel operation into a serialized +// operation via the Actor pattern[1]. // // [1]: https://en.wikipedia.org/wiki/Actor_model package actorify @@ -14,11 +15,17 @@ func z[Z any]() Z { } var ( + // ErrActorDied is returned when the actor inbox or reply channel was closed. ErrActorDied = errors.New("actorify: the actor inbox or reply channel was closed") ) +// Handler is a function alias for the underlying logic the Actor should call. type Handler[Input, Output any] func(ctx context.Context, input Input) (Output, error) +// Actor is a serializing wrapper that runs a function in a background goroutine. +// Whenever the Call method is invoked, a message is sent to the actor's inbox and then +// the callee waits for a response. Depending on how busy the actor is, this may take +// a moment. type Actor[Input, Output any] struct { handler Handler[Input, Output] inbox chan *message[Input, Output] @@ -35,6 +42,8 @@ type reply[Output any] struct { err error } +// New constructs a new Actor and starts its background thread. Cancel the context and you cancel +// the Actor. func New[Input, Output any](ctx context.Context, handler Handler[Input, Output]) *Actor[Input, Output] { result := &Actor[Input, Output]{ handler: handler, @@ -73,6 +82,10 @@ func (a *Actor[Input, Output]) handle(ctx context.Context) { } } +// Call calls the Actor with a given Input and returns the handler's Output. +// +// This only works with unary functions by design. If you need to have more inputs, define +// a struct type to use as a container. func (a *Actor[Input, Output]) Call(ctx context.Context, input Input) (Output, error) { replyCh := make(chan reply[Output]) diff --git a/lib/store/actorifiedstore.go b/lib/store/actorifiedstore.go index 366ad471..d495736e 100644 --- a/lib/store/actorifiedstore.go +++ b/lib/store/actorifiedstore.go @@ -41,6 +41,30 @@ func NewActorifiedStore(backend Interface) *ActorifiedStore { func (a *ActorifiedStore) Close() { a.cancel() } +func (a *ActorifiedStore) Delete(ctx context.Context, key string) error { + if _, err := a.deleteActor.Call(ctx, key); err != nil { + return err + } + + return nil +} + +func (a *ActorifiedStore) Get(ctx context.Context, key string) ([]byte, error) { + return a.getActor.Call(ctx, key) +} + +func (a *ActorifiedStore) Set(ctx context.Context, key string, value []byte, expiry time.Duration) error { + if _, err := a.setActor.Call(ctx, &actorSetReq{ + key: key, + value: value, + expiry: expiry, + }); err != nil { + return err + } + + return nil +} + func (a *ActorifiedStore) actorDelete(ctx context.Context, key string) (unit, error) { if err := a.Interface.Delete(ctx, key); err != nil { return unit{}, err