Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(cron): replace cron implementation. #226

Merged
merged 22 commits into from
Jan 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions c.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/go-kit/log"
"github.com/knadh/koanf/providers/confmap"
"github.com/knadh/koanf/providers/file"
"github.com/spf13/cobra"
"go.uber.org/dig"
)

Expand All @@ -32,7 +33,7 @@ type C struct {
Env contract.Env
contract.ConfigAccessor
logging.LevelLogger
contract.Container
*container.Container
contract.Dispatcher
di *dig.Container
}
Expand Down Expand Up @@ -224,7 +225,7 @@ func (c *C) AddModule(modules ...interface{}) {
}
}

// Provide adds a dependencies provider to the core. Note the dependency provider
// Provide adds dependencies provider to the core. Note the dependency provider
// must be a function in the form of:
//
// func(foo Foo) Bar
Expand Down Expand Up @@ -373,7 +374,18 @@ func (c *C) Serve(ctx context.Context) error {
})
}

// AddModuleFunc add the module after Invoking its' constructor. Clean up
// Shutdown iterates through every CloserProvider registered in the container,
// and calls them in the reversed order of registration.
func (c *C) Shutdown() {
modules := c.Modules()
for i := range modules {
if closer, ok := modules[len(modules)-i-1].(CloserProvider); ok {
closer.ProvideCloser()
}
}
}

// AddModuleFunc add the module after Invoking its constructor. Clean up
// functions and errors are handled automatically.
func (c *C) AddModuleFunc(constructor interface{}) {
c.provide(constructor)
Expand Down Expand Up @@ -404,6 +416,17 @@ func (c *C) AddModuleFunc(constructor interface{}) {
}
}

// ApplyRootCommand iterates through every CommandProvider registered in the container,
// and introduce the root *cobra.Command to everyone.
func (c *C) ApplyRootCommand(command *cobra.Command) {
modules := c.Modules()
for i := range modules {
if p, ok := modules[i].(CommandProvider); ok {
p.ProvideCommand(command)
}
}
}

// Invoke runs the given function after instantiating its dependencies. Any
// arguments that the function has are treated as its dependencies. The
// dependencies are instantiated in an unspecified order along with any
Expand Down
16 changes: 16 additions & 0 deletions c_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,19 @@ func TestC_cleanup(t *testing.T) {
assert.True(t, dependencyCleanupCalled)
assert.True(t, moduleCleanupCalled)
}

type closer func()

func (f closer) ProvideCloser() {
f()
}

func TestContainer_Shutdown(t *testing.T) {
seq := 0
container := New()
container.AddModule(closer(func() { assert.Equal(t, 2, seq); seq = 1 }))
container.AddModule(closer(func() { assert.Equal(t, 3, seq); seq = 2 }))
container.AddModule(closer(func() { assert.Equal(t, 0, seq); seq = 3 }))
container.Shutdown()
assert.Equal(t, 1, seq)
}
110 changes: 1 addition & 109 deletions container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,87 +5,13 @@ package container

import (
"github.com/DoNewsCode/core/contract"
"github.com/gorilla/mux"
"github.com/oklog/run"
"github.com/robfig/cron/v3"
"github.com/spf13/cobra"
"google.golang.org/grpc"
)

var _ contract.Container = (*Container)(nil)

// CronProvider provides cron jobs.
type CronProvider interface {
ProvideCron(crontab *cron.Cron)
}

// CommandProvider provides cobra.Command.
type CommandProvider interface {
ProvideCommand(command *cobra.Command)
}

// HTTPProvider provides http services.
type HTTPProvider interface {
ProvideHTTP(router *mux.Router)
}

// GRPCProvider provides gRPC services.
type GRPCProvider interface {
ProvideGRPC(server *grpc.Server)
}

// CloserProvider provides a shutdown function that will be called when service exits.
type CloserProvider interface {
ProvideCloser()
}

// RunProvider provides a runnable actor. Use it to register any server-like
// actions. For example, kafka consumer can be started here.
type RunProvider interface {
ProvideRunGroup(group *run.Group)
}

// Container holds all modules registered.
type Container struct {
httpProviders []func(router *mux.Router)
grpcProviders []func(server *grpc.Server)
closerProviders []func()
runProviders []func(g *run.Group)
modules []interface{}
cronProviders []func(crontab *cron.Cron)
commandProviders []func(command *cobra.Command)
}

// ApplyRouter iterates through every HTTPProvider registered in the container,
// and introduce the router to everyone.
func (c *Container) ApplyRouter(router *mux.Router) {
for _, p := range c.httpProviders {
p(router)
}
}

// ApplyGRPCServer iterates through every GRPCProvider registered in the container,
// and introduce a *grpc.Server to everyone.
func (c *Container) ApplyGRPCServer(server *grpc.Server) {
for _, p := range c.grpcProviders {
p(server)
}
}

// Shutdown iterates through every CloserProvider registered in the container,
// and calls them in the reversed order of registration.
func (c *Container) Shutdown() {
for i := len(c.closerProviders) - 1; i >= 0; i-- {
c.closerProviders[i]()
}
}

// ApplyRunGroup iterates through every RunProvider registered in the container,
// and introduce the *run.Group to everyone.
func (c *Container) ApplyRunGroup(g *run.Group) {
for _, p := range c.runProviders {
p(g)
}
modules []interface{}
}

// Modules returns all modules in the container. This method is used to scan for
Expand All @@ -107,40 +33,6 @@ func (c *Container) Modules() []interface{} {
return c.modules
}

// ApplyCron iterates through every CronProvider registered in the container,
// and introduce the *cron.Cron to everyone.
func (c *Container) ApplyCron(crontab *cron.Cron) {
for _, p := range c.cronProviders {
p(crontab)
}
}

// ApplyRootCommand iterates through every CommandProvider registered in the container,
// and introduce the root *cobra.Command to everyone.
func (c *Container) ApplyRootCommand(command *cobra.Command) {
for _, p := range c.commandProviders {
p(command)
}
}

func (c *Container) AddModule(module interface{}) {
if p, ok := module.(HTTPProvider); ok {
c.httpProviders = append(c.httpProviders, p.ProvideHTTP)
}
if p, ok := module.(GRPCProvider); ok {
c.grpcProviders = append(c.grpcProviders, p.ProvideGRPC)
}
if p, ok := module.(CronProvider); ok {
c.cronProviders = append(c.cronProviders, p.ProvideCron)
}
if p, ok := module.(RunProvider); ok {
c.runProviders = append(c.runProviders, p.ProvideRunGroup)
}
if p, ok := module.(CommandProvider); ok {
c.commandProviders = append(c.commandProviders, p.ProvideCommand)
}
if p, ok := module.(CloserProvider); ok {
c.closerProviders = append(c.closerProviders, p.ProvideCloser)
}
c.modules = append(c.modules, module)
}
57 changes: 1 addition & 56 deletions container/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,9 @@ package container
import (
"testing"

"github.com/gorilla/mux"
"github.com/oklog/run"
"github.com/robfig/cron/v3"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
)

type mock struct{}

func (m mock) ProvideRunGroup(group *run.Group) {
panic("implement me")
}

func (m mock) ProvideGRPC(server *grpc.Server) {
panic("implement me")
}

func (m mock) ProvideHTTP(router *mux.Router) {
panic("implement me")
}

func (m mock) ProvideCron(crontab *cron.Cron) {
panic("implement me")
}

func (m mock) ProvideCommand(command *cobra.Command) {
panic("implement me")
}

func TestContainer_AddModule(t *testing.T) {
cases := []struct {
name string
Expand All @@ -43,19 +16,7 @@ func TestContainer_AddModule(t *testing.T) {
"any",
"foo",
func(t *testing.T, container Container) {
assert.Contains(t, container.modules, "foo")
},
},
{
"mock",
mock{},
func(t *testing.T, container Container) {
assert.Len(t, container.runProviders, 1)
assert.Len(t, container.httpProviders, 1)
assert.Len(t, container.grpcProviders, 1)
assert.Len(t, container.cronProviders, 1)
assert.Len(t, container.commandProviders, 1)
assert.Len(t, container.closerProviders, 0)
assert.Contains(t, container.Modules(), "foo")
},
},
}
Expand All @@ -70,19 +31,3 @@ func TestContainer_AddModule(t *testing.T) {
})
}
}

type closer func()

func (f closer) ProvideCloser() {
f()
}

func TestContainer_Shutdown(t *testing.T) {
seq := 0
container := Container{}
container.AddModule(closer(func() { assert.Equal(t, 2, seq); seq = 1 }))
container.AddModule(closer(func() { assert.Equal(t, 3, seq); seq = 2 }))
container.AddModule(closer(func() { assert.Equal(t, 0, seq); seq = 3 }))
container.Shutdown()
assert.Equal(t, 1, seq)
}
15 changes: 0 additions & 15 deletions contract/container.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
package contract

import (
"github.com/gorilla/mux"
"github.com/oklog/run"
"github.com/robfig/cron/v3"
"github.com/spf13/cobra"
"google.golang.org/grpc"
)

// Container holds modules.
type Container interface {
ApplyRouter(router *mux.Router)
ApplyGRPCServer(server *grpc.Server)
ApplyCron(crontab *cron.Cron)
ApplyRunGroup(g *run.Group)
ApplyRootCommand(command *cobra.Command)
Shutdown()
Modules() []interface{}
AddModule(module interface{})
}
19 changes: 19 additions & 0 deletions cron/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cron

import (
"time"

"github.com/robfig/cron/v3"
)

// Config is the configuration for the cron package.
type Config struct {
// Parser is the parser to parse cron expressions.
Parser cron.ScheduleParser
// Location is the timezone to use in parsing cron expressions.
Location *time.Location
// GlobalOptions are the job options that are applied to all jobs.
GlobalOptions []JobOption
// EnableSeconds is whether to enable seconds in the cron expression.
EnableSeconds bool
}
Loading