Skip to content

Commit 2850434

Browse files
committed
refactor(application): reorganize lifecycle hooks and move interfaces to separate files
feat: add collectHooks method to automatically collect lifecycle hooks from loaded goners refactor: move Default application instance and related methods to default.go refactor: move lifecycle interfaces to stage_interface.go and update mock generation test: add TestApplication_collectHooks to verify hook collection order
1 parent 7acfff5 commit 2850434

File tree

8 files changed

+763
-466
lines changed

8 files changed

+763
-466
lines changed

application.go

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ type Application struct {
2020
signal chan os.Signal
2121
}
2222

23-
var Default = NewApp()
24-
2523
// NewApp creates and initializes a new Application instance.
2624
// It creates an empty Application struct and calls init() to:
2725
// 1. Initialize signal channel
@@ -80,10 +78,6 @@ func (s *Application) Load(goner Goner, options ...Option) *Application {
8078
return s
8179
}
8280

83-
func Load(goner Goner, options ...Option) *Application {
84-
return Default.Load(goner, options...)
85-
}
86-
8781
// Loads executes multiple LoadFuncs in sequence to load goner for Application
8882
// Parameters:
8983
// - loads: Variadic LoadFunc parameters that will be executed in order
@@ -100,10 +94,6 @@ func (s *Application) Loads(loads ...LoadFunc) *Application {
10094
return s
10195
}
10296

103-
func Loads(loads ...LoadFunc) *Application {
104-
return Default.Loads(loads...)
105-
}
106-
10797
// BeforeStart registers a function to be called before starting the application.
10898
// The function will be executed before any daemons are started.
10999
// Returns the Application instance for method chaining.
@@ -167,13 +157,6 @@ func (s *Application) End() *Application {
167157
return s
168158
}
169159

170-
// End triggers application termination
171-
// It terminates the application by sending a SIGINT signal to the default Application instance
172-
// This is a convenience method equivalent to calling Default.End()
173-
func End() {
174-
Default.End()
175-
}
176-
177160
func (s *Application) start() {
178161
for _, fn := range s.beforeStartHooks {
179162
fn()
@@ -215,6 +198,34 @@ func (s *Application) install() {
215198
}
216199
}
217200

201+
func (s *Application) collectHooks() {
202+
coffins := s.loader.iKeeper.getAllCoffins()
203+
for _, co := range coffins {
204+
if co.goner != nil {
205+
if start, ok := co.goner.(BeforeStarter); ok {
206+
s.beforeStart(func() {
207+
start.BeforeStart()
208+
})
209+
}
210+
if afterStart, ok := co.goner.(AfterStarter); ok {
211+
s.afterStart(func() {
212+
afterStart.AfterStart()
213+
})
214+
}
215+
if stop, ok := co.goner.(BeforeStoper); ok {
216+
s.beforeStop(func() {
217+
stop.BeforeStop()
218+
})
219+
}
220+
if afterStop, ok := co.goner.(AfterStoper); ok {
221+
s.afterStop(func() {
222+
afterStop.AfterStop()
223+
})
224+
}
225+
}
226+
}
227+
}
228+
218229
// Run initializes the application, injects dependencies into the provided function,
219230
// executes it, and then performs cleanup.
220231
// The function can have dependencies that will be automatically injected.
@@ -224,6 +235,7 @@ func (s *Application) install() {
224235
// - funcList: The function to execute with injected dependencies
225236
func (s *Application) Run(funcList ...any) {
226237
s.install()
238+
s.collectHooks()
227239
s.start()
228240

229241
var options []RunOption
@@ -247,8 +259,11 @@ func (s *Application) Run(funcList ...any) {
247259
s.stop()
248260
}
249261

250-
func Run(fn ...any) {
251-
Default.Run(fn...)
262+
// Serve initializes the application, starts all daemons, and waits for termination signal.
263+
// After receiving termination signal, performs cleanup by stopping all daemons.
264+
func (s *Application) Serve(funcList ...any) {
265+
funcList = append(funcList, OpWaitEnd())
266+
s.Run(funcList...)
252267
}
253268

254269
type RunOption interface {
@@ -265,17 +280,6 @@ func OpWaitEnd() RunOption {
265280
return waitEnd{}
266281
}
267282

268-
// Serve initializes the application, starts all daemons, and waits for termination signal.
269-
// After receiving termination signal, performs cleanup by stopping all daemons.
270-
func (s *Application) Serve(funcList ...any) {
271-
funcList = append(funcList, OpWaitEnd())
272-
s.Run(funcList...)
273-
}
274-
275-
func Serve() {
276-
Default.Serve()
277-
}
278-
279283
type TestFlag interface {
280284
forTest()
281285
}
@@ -291,11 +295,6 @@ func (s *Application) Test(fn any) {
291295
s.Run(fn)
292296
}
293297

294-
// Test for run tests
295-
func Test(fn any) {
296-
Default.Test(fn)
297-
}
298-
299298
// RunTest Deprecated, use Test instead
300299
func RunTest(fn any, priests ...LoadFunc) {
301300
NewApp(priests...).Test(fn)

application_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gone_test
22

33
import (
44
"errors"
5+
"go.uber.org/mock/gomock"
56
"reflect"
67
"strings"
78
"sync"
@@ -558,3 +559,61 @@ func TestEnd(t *testing.T) {
558559
}).
559560
Serve()
560561
}
562+
563+
func TestApplication_collectHooks(t *testing.T) {
564+
controller := gomock.NewController(t)
565+
defer controller.Finish()
566+
567+
var order, beforeStartOrder, afterStartOrder, beforeStopOrder, afterStopOrder int
568+
569+
starter := gone.NewMockBeforeStarter(controller)
570+
starter.EXPECT().BeforeStart().Do(func() {
571+
order++
572+
beforeStartOrder = order
573+
})
574+
afterStarter := gone.NewMockAfterStarter(controller)
575+
afterStarter.EXPECT().AfterStart().Do(func() {
576+
order++
577+
afterStartOrder = order
578+
})
579+
580+
stoper := gone.NewMockBeforeStoper(controller)
581+
stoper.EXPECT().BeforeStop().Do(func() {
582+
order++
583+
beforeStopOrder = order
584+
})
585+
586+
afterStoper := gone.NewMockAfterStoper(controller)
587+
588+
afterStoper.EXPECT().AfterStop().Do(func() {
589+
order++
590+
afterStopOrder = order
591+
})
592+
gone.
593+
NewApp().
594+
Load(stoper).
595+
Load(afterStoper).
596+
Load(starter).
597+
Load(afterStarter).
598+
Run(func() {
599+
if beforeStartOrder != 1 {
600+
t.Errorf("beforeStartOrder = %d, want %d", beforeStartOrder, 1)
601+
}
602+
if afterStartOrder != 2 {
603+
t.Errorf("afterStartOrder = %d, want %d", afterStartOrder, 2)
604+
}
605+
if beforeStopOrder != 0 {
606+
t.Errorf("beforeStopOrder = %d, want %d", beforeStopOrder, 0)
607+
}
608+
if afterStopOrder != 0 {
609+
t.Errorf("afterStopOrder = %d, want %d", afterStopOrder, 0)
610+
}
611+
})
612+
613+
if beforeStopOrder != 3 {
614+
t.Errorf("beforeStopOrder = %d, want %d", beforeStopOrder, 3)
615+
}
616+
if afterStopOrder != 4 {
617+
t.Errorf("afterStopOrder = %d, want %d", afterStopOrder, 4)
618+
}
619+
}

default.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package gone
2+
3+
// Default is a singleton instance of Application, used to simplify common usage patterns.
4+
var Default = NewApp()
5+
6+
// Loads uses the default application instance to load multiple LoadFunc functions.
7+
// Parameters:
8+
// - loads: One or more LoadFunc functions that will be executed in sequence
9+
//
10+
// Returns:
11+
// - *Application: Returns the default application instance for method chaining
12+
func Loads(loads ...LoadFunc) *Application {
13+
return Default.Loads(loads...)
14+
}
15+
16+
// Load uses the default application instance to load a Goner with optional configuration options.
17+
// Parameters:
18+
// - goner: The Goner instance to load
19+
// - options: Optional configuration options for the Goner
20+
//
21+
// Returns:
22+
// - *Application: Returns the default application instance for method chaining
23+
func Load(goner Goner, options ...Option) *Application {
24+
return Default.Load(goner, options...)
25+
}
26+
27+
// Run executes one or more functions using the default application instance.
28+
// These functions can have dependencies that will be automatically injected.
29+
// Parameters:
30+
// - fn: A variadic list of functions to execute with injected dependencies
31+
func Run(fn ...any) {
32+
Default.Run(fn...)
33+
}
34+
35+
// Serve starts all daemons and waits for termination signal using the default application instance.
36+
// This function will start all registered daemons and block until a shutdown signal is received.
37+
func Serve() {
38+
Default.Serve()
39+
}
40+
41+
// End triggers application termination
42+
// It terminates the application by sending a SIGINT signal to the default Application instance
43+
// This is a convenience method equivalent to calling Default.End()
44+
func End() {
45+
Default.End()
46+
}
47+
48+
// Test runs tests using the default application instance.
49+
// Parameters:
50+
// - fn: The test function to execute with injected dependencies
51+
func Test(fn any) {
52+
Default.Test(fn)
53+
}

iface.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ type FuncInjectHook func(pt reflect.Type, i int, injected bool) any
8282

8383
//go:generate mockgen -source=./iface.go -package=gone -destination=iface_mock.go
8484
//go:generate mockgen -source=./interface.go -package=gone -destination=interface_mock.go
85+
//go:generate mockgen -source=./stage_interface.go -package=gone -destination=stage_mock.go
8586
//go:generate mockgen -source=./logger.go -package=gone -destination=./logger_mock.go
8687
//go:generate mockgen -source=./config.go -package=gone -destination=./config_mock.go
8788

0 commit comments

Comments
 (0)