Skip to content

Commit 94a860e

Browse files
authored
Merge pull request #86 from gone-io/feature/patch-stage
refactor(lifecycle): improve component lifecycle documentation and sorting
2 parents 209d740 + 0131f19 commit 94a860e

File tree

4 files changed

+397
-90
lines changed

4 files changed

+397
-90
lines changed

application.go

Lines changed: 135 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,27 @@ import (
66
"syscall"
77
)
88

9+
// Application represents the core container and orchestrator for the Gone framework.
10+
// Think of it as the "command center" or "central dispatch" of your application - it's like
11+
// the conductor of an orchestra who knows every musician (component), their instruments (capabilities),
12+
// and how they should work together to create beautiful music (your application).
13+
//
14+
// The Application acts as the central hub that:
15+
// - Loads and manages all components (like a "personnel manager")
16+
// - Handles dependency injection between components (like a "matchmaker")
17+
// - Manages application lifecycle with hooks (like a "stage director")
18+
// - Provides access to components via the GonerKeeper interface (like a "directory service")
19+
//
20+
// Design Philosophy:
21+
// - Single Responsibility: Each Application instance manages one complete application context
22+
// - Composition over Inheritance: Built by composing various specialized components
23+
// - Encapsulation: Internal complexity is hidden behind simple, intuitive interfaces
24+
//
25+
// Key responsibilities:
26+
// - Component registration and loading ("hiring and onboarding")
27+
// - Dependency resolution and injection ("team building and collaboration")
28+
// - Lifecycle management with hooks ("project management")
29+
// - Graceful shutdown handling ("orderly dismissal")
930
type Application struct {
1031
Flag
1132

@@ -21,6 +42,15 @@ type Application struct {
2142
}
2243

2344
// NewApp creates and initializes a new Application instance.
45+
// Think of it as "founding a new company" where LoadFuncs are like "department setup plans"
46+
// that define how to establish different parts of your application. Each LoadFunc knows
47+
// how to "hire" and "organize" specific types of components.
48+
//
49+
// The Creation Process:
50+
// - Establishes the "company headquarters" (Application instance)
51+
// - Registers "department setup plans" (LoadFuncs)
52+
// - Prepares the "organizational structure" for component management
53+
//
2454
// It creates an empty Application struct and calls init() to:
2555
// 1. Initialize signal channel
2656
// 2. Create new Core
@@ -55,11 +85,19 @@ func (s *Application) init() *Application {
5585
}
5686

5787
// Load loads a Goner into the Application's loader with optional configuration options.
88+
// Think of it as "hiring a new employee" where you bring a specific person (component)
89+
// into your company (application) and give them their "employee handbook" (options).
5890
// It wraps the Core.Load() method and panics if loading fails.
5991
//
92+
// The Hiring Process:
93+
// - Verify the candidate has proper "credentials" (implements Goner interface)
94+
// - Assign them a unique "employee ID" (internal tracking)
95+
// - Set up their "workspace" and "job description" (configuration)
96+
// - Add them to the "company directory" (component registry)
97+
//
6098
// Parameters:
61-
// - goner: The Goner instance to load
62-
// - options: Optional configuration options for the Goner
99+
// - goner: The Goner instance to load - the "new hire"
100+
// - options: Optional configuration options for the Goner - the "employment terms"
63101
//
64102
// Available Options:
65103
// - Name(name string): Set custom name for the Goner
@@ -79,8 +117,16 @@ func (s *Application) Load(goner Goner, options ...Option) *Application {
79117
}
80118

81119
// Loads executes multiple LoadFuncs in sequence to load goner for Application
120+
// Think of it as "batch hiring" where you bring multiple new employees into your
121+
// company at once, like during a "recruitment drive" or "team expansion".
122+
//
123+
// The Batch Hiring Process:
124+
// - Process each LoadFunc in sequence
125+
// - Each LoadFunc acts like a "department setup plan"
126+
// - Stop the process if any "hiring" fails
127+
//
82128
// Parameters:
83-
// - loads: Variadic LoadFunc parameters that will be executed in order
129+
// - loads: Variadic LoadFunc parameters that will be executed in order - the "batch of hiring plans"
84130
//
85131
// Each LoadFunc typically loads goner components.
86132
// If any LoadFunc fails during execution, it will trigger a panic.
@@ -95,7 +141,16 @@ func (s *Application) Loads(loads ...LoadFunc) *Application {
95141
}
96142

97143
// BeforeStart registers a function to be called before starting the application.
98-
// The function will be executed before any daemons are started.
144+
// Think of it as scheduling a "pre-opening meeting" where you can perform final preparations
145+
// before your "business" officially opens its doors. The function will be executed before
146+
// any daemons are started.
147+
//
148+
// Typical Use Cases:
149+
// - Final system checks and validations
150+
// - Cache warming and data preloading
151+
// - External service connections
152+
// - Configuration validation
153+
//
99154
// Returns the Application instance for method chaining.
100155
func (s *Application) BeforeStart(fn Process) *Application {
101156
s.beforeStart(fn)
@@ -107,7 +162,16 @@ func (s *Application) beforeStart(fn Process) {
107162
}
108163

109164
// AfterStart registers a function to be called after starting the application.
110-
// The function will be executed after all daemons have been started.
165+
// Think of it as scheduling a "grand opening celebration" or "post-launch activities"
166+
// that happen after your "business" is officially open and running. The function will
167+
// be executed after all daemons have been started.
168+
//
169+
// Typical Use Cases:
170+
// - Success notifications and logging
171+
// - Health check registrations
172+
// - Monitoring and metrics setup
173+
// - External service announcements
174+
//
111175
// Returns the Application instance for method chaining.
112176
func (s *Application) AfterStart(fn Process) *Application {
113177
s.afterStart(fn)
@@ -119,7 +183,16 @@ func (s *Application) afterStart(fn Process) {
119183
}
120184

121185
// BeforeStop registers a function to be called before stopping the application.
122-
// The function will be executed before any daemons are stopped.
186+
// Think of it as scheduling "closing preparations" where you perform necessary tasks
187+
// before your "business" officially closes. The function will be executed before
188+
// any daemons are stopped.
189+
//
190+
// Typical Use Cases:
191+
// - Graceful connection closures
192+
// - Data persistence and state saving
193+
// - Resource cleanup and release
194+
// - Shutdown notifications
195+
//
123196
// Returns the Application instance for method chaining.
124197
func (s *Application) BeforeStop(fn Process) *Application {
125198
s.beforeStop(fn)
@@ -131,7 +204,16 @@ func (s *Application) beforeStop(fn Process) {
131204
}
132205

133206
// AfterStop registers a function to be called after stopping the application.
134-
// The function will be executed after all daemons have been stopped.
207+
// Think of it as "post-closure activities" that happen after your "business" has
208+
// officially closed its doors. The function will be executed after all daemons
209+
// have been stopped.
210+
//
211+
// Typical Use Cases:
212+
// - Final cleanup and resource release
213+
// - Shutdown success logging
214+
// - External service deregistration
215+
// - Final state persistence
216+
//
135217
// Returns the Application instance for method chaining.
136218
func (s *Application) AfterStop(fn Process) *Application {
137219
s.afterStop(fn)
@@ -143,6 +225,15 @@ func (s *Application) afterStop(fn Process) {
143225
}
144226

145227
// WaitEnd blocks until the application receives a termination signal (SIGINT, SIGTERM, or SIGQUIT).
228+
// Think of it as a "security guard" who watches the door and waits for the "closing time signal".
229+
// This method listens for termination signals (like Ctrl+C or system shutdown) and returns when
230+
// one is received, allowing for graceful shutdown procedures.
231+
//
232+
// Signal Monitoring:
233+
// - SIGINT: Usually triggered by Ctrl+C ("manual closing")
234+
// - SIGTERM: System shutdown or process termination ("scheduled closing")
235+
// - SIGQUIT: Quit signal ("emergency closing")
236+
//
146237
// Returns the Application instance for method chaining.
147238
func (s *Application) WaitEnd() *Application {
148239
signal.Notify(s.signal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
@@ -151,6 +242,10 @@ func (s *Application) WaitEnd() *Application {
151242
}
152243

153244
// End triggers application termination by sending a SIGINT signal.
245+
// Think of it as the "official closing procedure" where you send the "closing signal"
246+
// to initiate graceful shutdown. This method triggers application termination by
247+
// sending a SIGINT signal.
248+
//
154249
// Returns the Application instance for method chaining.
155250
func (s *Application) End() *Application {
156251
s.signal <- syscall.SIGINT
@@ -212,12 +307,12 @@ func (s *Application) collectHooks() {
212307
afterStart.AfterStart()
213308
})
214309
}
215-
if stop, ok := co.goner.(BeforeStoper); ok {
310+
if stop, ok := co.goner.(BeforeStopper); ok {
216311
s.beforeStop(func() {
217312
stop.BeforeStop()
218313
})
219314
}
220-
if afterStop, ok := co.goner.(AfterStoper); ok {
315+
if afterStop, ok := co.goner.(AfterStopper); ok {
221316
s.afterStop(func() {
222317
afterStop.AfterStop()
223318
})
@@ -228,11 +323,20 @@ func (s *Application) collectHooks() {
228323

229324
// Run initializes the application, injects dependencies into the provided function,
230325
// executes it, and then performs cleanup.
326+
// Think of it as "opening your business for a specific task" - you unlock the doors,
327+
// turn on all systems, perform the specific work, then properly close everything down.
231328
// The function can have dependencies that will be automatically injected.
232329
// Panics if dependency injection or execution fails.
233330
//
331+
// The Complete Business Day Process:
332+
// 1. "System setup" - Install and initialize all components
333+
// 2. "Team coordination" - Collect and register lifecycle hooks
334+
// 3. "Open for business" - Execute start procedures
335+
// 4. "Main work" - Execute provided functions with dependency injection
336+
// 5. "Proper closure" - Execute stop procedures
337+
//
234338
// Parameters:
235-
// - funcList: The function to execute with injected dependencies
339+
// - funcList: The function to execute with injected dependencies - the "main business tasks"
236340
func (s *Application) Run(funcList ...any) {
237341
s.install()
238342
s.collectHooks()
@@ -260,7 +364,14 @@ func (s *Application) Run(funcList ...any) {
260364
}
261365

262366
// Serve initializes the application, starts all daemons, and waits for termination signal.
367+
// Think of it as "opening your business for continuous operation" - you unlock the doors,
368+
// start all services, and keep the business running until you receive a "closing signal".
263369
// After receiving termination signal, performs cleanup by stopping all daemons.
370+
//
371+
// The Continuous Operation Process:
372+
// - Same as Run() but includes OpWaitEnd() to wait for termination signals
373+
// - Ideal for long-running applications like web servers or background services
374+
//
264375
func (s *Application) Serve(funcList ...any) {
265376
funcList = append(funcList, OpWaitEnd())
266377
s.Run(funcList...)
@@ -290,6 +401,20 @@ type testFlag struct {
290401

291402
func (*testFlag) forTest() {}
292403

404+
// Test runs the application in test mode with dependency injection.
405+
// Think of it as setting up a "testing laboratory" where you can experiment with your
406+
// components in a controlled environment. This method is designed for testing scenarios
407+
// where you need to execute test functions with proper dependency injection.
408+
//
409+
// The Testing Laboratory Process:
410+
// - Loads a test flag to indicate test mode
411+
// - Executes the test function using Run() with full dependency injection
412+
//
413+
// Key Features:
414+
// - Full dependency injection support
415+
// - Simplified execution for testing purposes
416+
// - Test mode indication via testFlag
417+
//
293418
func (s *Application) Test(fn any) {
294419
s.Load(&testFlag{})
295420
s.Run(fn)

core_keeper.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ func (s *keeper) getByTypeAndPattern(t reflect.Type, pattern string) (coffins []
3535
coffins = append(coffins, co)
3636
}
3737
}
38+
39+
SortCoffins(coffins)
3840
return coffins
3941
}
4042

0 commit comments

Comments
 (0)