Documentation
¶
Overview ¶
Package depman provides a simple dependency manager for resources. The basic idea is to write a specification for creating a resource, and then create the resource according to that specification. The specification is managed according to Go's comparison operation specification, and if the specifications are the same, the same resource will be returned. In other words, by creating the specification carefully, you can manage the extent to which resources are shared.
Index ¶
- Variables
- func ContextWithResourceManager(ctx context.Context, rm ResourceManager) context.Context
- func RequestResource[T any](ctx context.Context, spec ResourceSpec[T]) (T, error)
- func SetResource[T any](ctx context.Context, spec ResourceSpec[T], res T) error
- type CloseFn
- type ResourceManager
- type ResourceSpec
Examples ¶
Constants ¶
This section is empty.
Variables ¶
Functions ¶
func ContextWithResourceManager ¶ added in v0.2.0
func ContextWithResourceManager(ctx context.Context, rm ResourceManager) context.Context
func RequestResource ¶
func RequestResource[T any](ctx context.Context, spec ResourceSpec[T]) (T, error)
Example ¶
package main
import (
"context"
"errors"
"fmt"
"sync"
"github.com/vvakame/depman"
)
var mutex sync.Mutex
var intValue int
type SharedResourceSpec struct{}
func (spec SharedResourceSpec) CreateResource(ctx context.Context) (int, depman.CloseFn, error) {
mutex.Lock()
defer mutex.Unlock()
intValue++
return intValue, nil, nil
}
type DedicatedResourceSpec struct {
PtrValue *string
}
func (spec *DedicatedResourceSpec) CreateResource(ctx context.Context) (func(error), depman.CloseFn, error) {
var err error
retFn := func(closeErr error) {
err = closeErr
}
closeFun := func(ctx context.Context) error {
return err
}
return retFn, closeFun, nil
}
func main() {
m := depman.NewManager()
ctx := depman.ContextWithResourceManager(context.Background(), m)
// https://go.dev/ref/spec#Comparison_operators
// > Struct types are comparable if all their field types are comparable
// This means that the following comparison becomes true.
if (SharedResourceSpec{}) != (SharedResourceSpec{}) {
panic("unexpected behavior")
}
// run CreateResource method once
v, err := depman.RequestResource(ctx, SharedResourceSpec{})
if err != nil {
panic(err)
}
fmt.Println(v)
// request resource again.
// and its value is the same as the previous one.
// because the specification is the same.
v, err = depman.RequestResource(ctx, SharedResourceSpec{})
if err != nil {
panic(err)
}
fmt.Println(v)
err = m.CloseAll(ctx)
if err != nil {
panic(err)
}
m = depman.NewManager()
ctx = depman.ContextWithResourceManager(ctx, m)
// https://go.dev/ref/spec#Comparison_operators
// > Pointer types are comparable. Two pointer values are equal if they point to the same variable or if both have value nil.
// This means that the following comparison becomes false.
spec1 := &DedicatedResourceSpec{}
spec2 := &DedicatedResourceSpec{}
if (spec1) == (spec2) {
panic("unexpected behavior")
}
closeErr1 := errors.New("close error 1")
errFn1, err := depman.RequestResource(ctx, &DedicatedResourceSpec{})
if err != nil {
panic(err)
}
errFn1(closeErr1)
closeErr2 := errors.New("close error 2")
errFn2, err := depman.RequestResource(ctx, &DedicatedResourceSpec{})
if err != nil {
panic(err)
}
errFn2(closeErr2)
err = m.CloseAll(ctx)
if !errors.Is(err, closeErr1) {
panic("unexpected result")
}
if !errors.Is(err, closeErr2) {
panic("unexpected result")
}
}
Output: 1 1
Example (SpecCascade) ¶
package main
import (
"context"
"fmt"
"github.com/vvakame/depman"
)
type SumSpec struct {
Value int
current int
sum int
}
func (spec SumSpec) CreateResource(ctx context.Context) (int, depman.CloseFn, error) {
fmt.Println(spec.current)
if spec.Value == spec.current {
return spec.sum, nil, nil
}
nextSpec := SumSpec{
Value: spec.Value,
current: spec.current + 1,
sum: spec.sum + spec.current + 1,
}
v, err := depman.RequestResource(ctx, nextSpec)
return v, nil, err
}
func main() {
m := depman.NewManager()
ctx := depman.ContextWithResourceManager(context.Background(), m)
v, err := depman.RequestResource(ctx, SumSpec{Value: 10})
if err != nil {
panic(err)
}
fmt.Println(v)
// cached. so no output in resource creation process.
v, err = depman.RequestResource(ctx, SumSpec{Value: 10})
if err != nil {
panic(err)
}
fmt.Println(v)
}
Output: 0 1 2 3 4 5 6 7 8 9 10 55 55
func SetResource ¶ added in v0.1.1
func SetResource[T any](ctx context.Context, spec ResourceSpec[T], res T) error
Example ¶
package main
import (
"context"
"fmt"
"github.com/vvakame/depman"
)
type CallbackFnSpec struct {
Callback func()
}
func (spec *CallbackFnSpec) CreateResource(ctx context.Context) (int, depman.CloseFn, error) {
spec.Callback()
return 0, nil, nil
}
func main() {
m := depman.NewManager()
ctx := depman.ContextWithResourceManager(context.Background(), m)
spec := &CallbackFnSpec{
Callback: func() {
fmt.Println("callback")
},
}
err := depman.SetResource(ctx, spec, 100)
if err != nil {
panic(err)
}
// cached. so callback function never called.
v, err := depman.RequestResource(ctx, spec)
if err != nil {
panic(err)
}
fmt.Println(v)
}
Output: 100
Types ¶
type ResourceManager ¶
type ResourceManager interface {
CloseAll(ctx context.Context) error
// contains filtered or unexported methods
}
func NewManager ¶
func NewManager() ResourceManager
func ResourceManagerFromContext ¶ added in v0.2.0
func ResourceManagerFromContext(ctx context.Context) ResourceManager
Click to show internal directories.
Click to hide internal directories.