Skip to content

Commit

Permalink
Add module for server.
Browse files Browse the repository at this point in the history
  • Loading branch information
googollee committed Nov 4, 2023
1 parent 4df7e2a commit 261ac15
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 280 deletions.
9 changes: 6 additions & 3 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ type runtimeContext struct {
request *http.Request
responseWriter http.ResponseWriter
pathParams httprouter.Params
modules module.Modules
repo *module.Repo

logger *slog.Logger
reqCodec Codec
Expand All @@ -103,8 +103,11 @@ func getRuntimeContext(ctx Context) *runtimeContext {
}

func (c *runtimeContext) Value(key any) any {
if ret := c.modules.Value(key); ret != nil {
return ret
moduleKey, ok := key.(module.ModuleKey)
if ok {
if ret := c.repo.Value(moduleKey); ret != nil {
return ret
}
}

switch key {
Expand Down
16 changes: 9 additions & 7 deletions examples/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ func NewDB(ctx context.Context) (*DB, error) {
}, nil
}

func (d *DB) CheckHealthy(ctx context.Context) error {
func (d *DB) CheckHealth(ctx context.Context) error {
return nil
}

var ModuleDB = module.NewModule(NewDB)
var ModuleDB = module.New(NewDB)

type Cache struct {
Cache string
Expand All @@ -38,11 +38,11 @@ func NewCache(ctx context.Context) (*Cache, error) {
}, nil
}

func (c *Cache) CheckHealthy(ctx context.Context) error {
func (c *Cache) CheckHealth(ctx context.Context) error {
return nil
}

var ModuleCache = module.NewModule(NewCache)
var ModuleCache = module.New(NewCache)

type MessageQueue struct {
Queue string
Expand All @@ -54,11 +54,11 @@ func NewMQ(ctx context.Context) (*MessageQueue, error) {
}, nil
}

func (r *MessageQueue) CheckHealthy(ctx context.Context) error {
func (r *MessageQueue) CheckHealth(ctx context.Context) error {
return nil
}

var ModuleMQ = module.NewModule(NewMQ)
var ModuleMQ = module.New(NewMQ)

func Handler(ctx espresso.Context) error {
if err := ctx.Endpoint(http.MethodGet, "/").End(); err != nil {
Expand All @@ -76,7 +76,9 @@ func Handler(ctx espresso.Context) error {

func LaunchModule() (addr string, cancel func()) {
server, _ := espresso.New()
if err := server.AddModule(ModuleCache, ModuleMQ, ModuleDB); err != nil {

ctx := context.Background()
if err := server.AddModule(ctx, ModuleCache, ModuleMQ, ModuleDB); err != nil {
panic(err)
}

Expand Down
57 changes: 0 additions & 57 deletions module/build.go

This file was deleted.

59 changes: 59 additions & 0 deletions module/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package module

import "context"

type errBuildError struct {
name contextKey
err error
}

type buildContext struct {
context.Context
mod ModuleKey
dependOn map[contextKey]struct{}
repo *Repo
}

func newBuildContext(ctx context.Context, repo *Repo) *buildContext {
return &buildContext{
Context: ctx,
repo: repo,
}
}

func (ctx *buildContext) Child(mod ModuleKey) *buildContext {
return &buildContext{
Context: ctx.Context,
mod: mod,
dependOn: make(map[contextKey]struct{}),
repo: ctx.repo,
}
}

func (ctx *buildContext) Value(name any) any {
key, ok := name.(ModuleKey)
if !ok {
return ctx.Context.Value(name)
}

ctx.dependOn[key.contextKey()] = struct{}{}

if ret := ctx.repo.Value(key); ret != nil {
return ret
}

if err := key.build(ctx); err != nil {
panic(errBuildError{name: key.contextKey(), err: err})
}

return ctx.repo.Value(key)
}

func (ctx *buildContext) addInstance(instance Instance) {
deps := make([]contextKey, 0, len(ctx.dependOn))
for key := range ctx.dependOn {
deps = append(deps, key)
}

ctx.repo.addInstance(ctx.mod, deps, instance)
}
12 changes: 0 additions & 12 deletions module/manager.go

This file was deleted.

105 changes: 55 additions & 50 deletions module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,76 +2,81 @@ package module

import (
"context"
"errors"
"fmt"
"reflect"
)

var ErrModuleDependError = errors.New("depend error")
var ErrModuleNotFound = errors.New("not found module")
var errBuildError = errors.New("build error")

type nameKey string
type Instance interface {
CheckHealth(context.Context) error
}

type Module interface {
Name() nameKey
DependOn() []nameKey
CheckHealthy(context.Context) error
type BuildFunc[T Instance] func(context.Context) (T, error)

type ModuleKey interface {
contextKey() contextKey
build(*buildContext) error
}
type contextKey string

func CheckHealthy(ctx context.Context, names []nameKey) error {
errs := make(map[nameKey]error)
type Module[T Instance] struct {
ModuleKey
name contextKey
buildFn BuildFunc[T]
}

checkModuleHealthy(ctx, names, errs)
func New[T Instance](buildFunc BuildFunc[T]) Module[T] {
var t T
return Module[T]{
name: contextKey(reflect.TypeOf(t).String()),
buildFn: buildFunc,
}
}

if len(errs) != 0 {
ret := make([]error, 0, len(errs))
for name, err := range errs {
ret = append(ret, fmt.Errorf("module %s: %w", name, err))
}
return errors.Join(ret...)
func (m Module[T]) Value(ctx context.Context) (ret T) {
v := ctx.Value(m)
if v == nil {
return
}

return nil
return v.(T)
}

func checkModuleHealthy(ctx context.Context, names []nameKey, errs map[nameKey]error) {
for _, name := range names {
if _, ok := errs[name]; ok {
continue
}
func (m Module[T]) String() string {
return fmt.Sprintf("Module[%s]", m.name)
}

v := ctx.Value(name)
if v == nil {
errs[name] = ErrModuleNotFound
continue
}
module, ok := v.(Module)
if !ok {
errs[name] = ErrModuleNotFound
continue
}
func (m Module[T]) contextKey() contextKey {
return m.name
}

depHealthy := true
if deps := module.DependOn(); len(deps) != 0 {
checkModuleHealthy(ctx, deps, errs)
func (m Module[T]) build(ctx *buildContext) (err error) {
t := ctx.Value(m.name)
if t != nil {
return nil
}

for _, depname := range deps {
if errs[depname] != nil {
depHealthy = false
break
}
}
}
bctx := ctx.Child(m)

if !depHealthy {
errs[name] = ErrModuleDependError
continue
defer func() {
p := recover()
if p == nil {
return
}

if err := module.CheckHealthy(ctx); err != nil {
errs[name] = err
e, ok := p.(errBuildError)
if !ok {
panic(p)
}

err = fmt.Errorf("Module[%s] build error: %w", e.name, e.err)
}()

instance, err := m.buildFn(bctx)
if err != nil {
return fmt.Errorf("Module[%s] build error: %w", m.name, err)
}

bctx.addInstance(instance)

return nil
}
Loading

0 comments on commit 261ac15

Please sign in to comment.