Skip to content

Commit

Permalink
Lazy instantiation for services with side effects (#98)
Browse files Browse the repository at this point in the history
  • Loading branch information
mgdigital authored Jan 6, 2024
1 parent c054e6b commit 5d74cf6
Show file tree
Hide file tree
Showing 53 changed files with 875 additions and 648 deletions.
6 changes: 4 additions & 2 deletions internal/app/appfx/module.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package appfx

import (
"github.com/bitmagnet-io/bitmagnet/internal/app/cmd/searchcmd"
"github.com/bitmagnet-io/bitmagnet/internal/app/cmd/torrentcmd"
"github.com/bitmagnet-io/bitmagnet/internal/blocking/blockingfx"
"github.com/bitmagnet-io/bitmagnet/internal/boilerplate/app/boilerplateappfx"
"github.com/bitmagnet-io/bitmagnet/internal/boilerplate/httpserver/httpserverfx"
"github.com/bitmagnet-io/bitmagnet/internal/classifier/classifierfx"
"github.com/bitmagnet-io/bitmagnet/internal/database/databasefx"
"github.com/bitmagnet-io/bitmagnet/internal/database/migrations"
"github.com/bitmagnet-io/bitmagnet/internal/database/search/warmer"
"github.com/bitmagnet-io/bitmagnet/internal/dhtcrawler/dhtcrawlerfx"
"github.com/bitmagnet-io/bitmagnet/internal/gql/gqlfx"
"github.com/bitmagnet-io/bitmagnet/internal/importer/importerfx"
Expand Down Expand Up @@ -43,10 +43,12 @@ func New() fx.Option {
versionfx.New(),
// cli commands:
fx.Provide(
searchcmd.New,
torrentcmd.New,
),
fx.Provide(webui.New),
fx.Decorate(migrations.NewDecorator),
fx.Decorate(
warmer.NewDecorator,
),
)
}
111 changes: 0 additions & 111 deletions internal/app/cmd/searchcmd/command.go

This file was deleted.

9 changes: 7 additions & 2 deletions internal/app/cmd/torrentcmd/command.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package torrentcmd

import (
"github.com/bitmagnet-io/bitmagnet/internal/boilerplate/lazy"
"github.com/bitmagnet-io/bitmagnet/internal/classifier"
"github.com/bitmagnet-io/bitmagnet/internal/protocol"
"github.com/bitmagnet-io/bitmagnet/internal/protocol/metainfo/metainforequester"
Expand All @@ -13,7 +14,7 @@ import (
type Params struct {
fx.In
MetaInfoRequester metainforequester.Requester
Classifier classifier.Classifier
Classifier lazy.Lazy[classifier.Classifier]
Logger *zap.SugaredLogger
}

Expand All @@ -34,11 +35,15 @@ func New(p Params) (Result, error) {
},
},
Action: func(ctx *cli.Context) error {
c, err := p.Classifier.Get()
if err != nil {
return err
}
infoHash, err := protocol.ParseID(ctx.String("infoHash"))
if err != nil {
return err
}
return p.Classifier.Classify(ctx.Context, infoHash)
return c.Classify(ctx.Context, infoHash)
},
},
{
Expand Down
29 changes: 19 additions & 10 deletions internal/blocking/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package blocking

import (
"context"
"github.com/bitmagnet-io/bitmagnet/internal/boilerplate/lazy"
"github.com/bitmagnet-io/bitmagnet/internal/database/dao"
"github.com/bitmagnet-io/bitmagnet/internal/protocol"
"go.uber.org/fx"
Expand All @@ -10,27 +11,35 @@ import (

type Params struct {
fx.In
Dao *dao.Query
Dao lazy.Lazy[*dao.Query]
}

type Result struct {
fx.Out
Manager Manager
Manager lazy.Lazy[Manager]
AppHook fx.Hook `group:"app_hooks"`
}

func New(params Params) Result {
m := &manager{
dao: params.Dao,
buffer: make(map[protocol.ID]struct{}, 1000),
maxBufferSize: 1000,
maxFlushWait: time.Minute * 5,
}
lazyManager := lazy.New[Manager](func() (Manager, error) {
d, err := params.Dao.Get()
if err != nil {
return nil, err
}
return &manager{
dao: d,
buffer: make(map[protocol.ID]struct{}, 1000),
maxBufferSize: 1000,
maxFlushWait: time.Minute * 5,
}, nil
})
return Result{
Manager: m,
Manager: lazyManager,
AppHook: fx.Hook{
OnStop: func(ctx context.Context) error {
return m.Flush(ctx)
return lazyManager.IfInitialized(func(m Manager) error {
return m.Flush(ctx)
})
},
},
}
Expand Down
84 changes: 42 additions & 42 deletions internal/boilerplate/httpserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,53 +24,53 @@ type Params struct {

type Result struct {
fx.Out
Gin *gin.Engine
Server *http.Server
Worker worker.Worker `group:"workers"`
}

func New(p Params) (r Result, err error) {
gin.SetMode(p.Config.GinMode)
g := gin.New()
g.Use(ginzap.Ginzap(p.Logger.Named("gin"), time.RFC3339, true), gin.Recovery())
options, optionsErr := resolveOptions(p.Config.Options, p.Options)
if optionsErr != nil {
err = optionsErr
return
}
for _, o := range options {
if buildErr := o.Apply(g); buildErr != nil {
err = buildErr
return
}
}
s := &http.Server{
Addr: p.Config.LocalAddress,
Handler: g.Handler(),
}
r.Worker = worker.NewWorker(
"http_server",
fx.Hook{
OnStart: func(ctx context.Context) error {
ln, listenErr := net.Listen("tcp", s.Addr)
if listenErr != nil {
return listenErr
}
go (func() {
serveErr := s.Serve(ln)
if !errors.Is(serveErr, http.ErrServerClosed) {
panic(serveErr)
func New(p Params) Result {
var s *http.Server
return Result{
Worker: worker.NewWorker(
"http_server",
fx.Hook{
OnStart: func(ctx context.Context) error {
gin.SetMode(p.Config.GinMode)
g := gin.New()
g.Use(ginzap.Ginzap(p.Logger.Named("gin"), time.RFC3339, true), gin.Recovery())
options, optionsErr := resolveOptions(p.Config.Options, p.Options)
if optionsErr != nil {
return optionsErr
}
})()
return nil
},
OnStop: func(ctx context.Context) error {
return s.Shutdown(ctx)
for _, o := range options {
if buildErr := o.Apply(g); buildErr != nil {
return buildErr
}
}
s = &http.Server{
Addr: p.Config.LocalAddress,
Handler: g.Handler(),
}
ln, listenErr := net.Listen("tcp", s.Addr)
if listenErr != nil {
return listenErr
}
go (func() {
serveErr := s.Serve(ln)
if !errors.Is(serveErr, http.ErrServerClosed) {
panic(serveErr)
}
})()
return nil
},
OnStop: func(ctx context.Context) error {
if s == nil {
return nil
}
return s.Shutdown(ctx)
},
},
},
)
r.Gin = g
return
),
}
}

func resolveOptions(param []string, options []Option) ([]Option, error) {
Expand Down
40 changes: 40 additions & 0 deletions internal/boilerplate/lazy/lazy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package lazy

import "sync"

type Lazy[T any] interface {
Get() (T, error)
// IfInitialized calls the given function if the value has been initialized (useful for shutdown logic)
IfInitialized(func(T) error) error
}

func New[T any](fn func() (T, error)) Lazy[T] {
return &lazy[T]{fn: fn}
}

type lazy[T any] struct {
fn func() (T, error)
mtx sync.Mutex
v T
err error
done bool
}

func (l *lazy[T]) Get() (T, error) {
l.mtx.Lock()
defer l.mtx.Unlock()
if !l.done {
l.v, l.err = l.fn()
l.done = true
}
return l.v, l.err
}

func (l *lazy[T]) IfInitialized(fn func(T) error) error {
l.mtx.Lock()
defer l.mtx.Unlock()
if l.done {
return fn(l.v)
}
return nil
}
Loading

0 comments on commit 5d74cf6

Please sign in to comment.