-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.go
More file actions
386 lines (328 loc) · 11.2 KB
/
app.go
File metadata and controls
386 lines (328 loc) · 11.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
package forge
import (
"context"
"os"
"time"
)
// App represents a Forge application with lifecycle management.
type App interface {
// Core components
Container() Container
Router() Router
Config() ConfigManager
Logger() Logger
Metrics() Metrics
HealthManager() HealthManager
LifecycleManager() LifecycleManager
// Lifecycle
Start(ctx context.Context) error
Stop(ctx context.Context) error
Run() error // Blocks until shutdown signal
// Registration
RegisterService(name string, factory Factory, opts ...RegisterOption) error
RegisterController(controller Controller) error
RegisterExtension(ext Extension) error
// Lifecycle hooks - convenience methods
RegisterHook(phase LifecyclePhase, hook LifecycleHook, opts LifecycleHookOptions) error
RegisterHookFn(phase LifecyclePhase, name string, hook LifecycleHook) error
// Information
Name() string
Version() string
Environment() string
StartTime() time.Time
Uptime() time.Duration
// Extensions
Extensions() []Extension
GetExtension(name string) (Extension, error)
// Configuration queries
MigrationsDisabled() bool
}
// AppConfig configures the application.
type AppConfig struct {
// Basic info
Name string
Version string
Description string
Environment string // "development", "staging", "production"
// Components
ConfigManager ConfigManager
Logger Logger
Metrics Metrics
// Router options
RouterOptions []RouterOption
// Observability
MetricsConfig MetricsConfig
HealthConfig HealthConfig
// Profiling
EnablePprof bool // Enable pprof profiling endpoints at /_/debug/pprof (default: false)
PprofPrefix string // URL prefix for pprof endpoints (default: "/_/debug/pprof")
ErrorHandler ErrorHandler
// Server
HTTPAddress string // Default: ":8080"
HTTPTimeout time.Duration // Default: 30s
// Shutdown
ShutdownTimeout time.Duration // Default: 30s
ShutdownSignals []os.Signal // Default: SIGINT, SIGTERM
// Health
HealthGracePeriod time.Duration // Grace period after startup during which health endpoints always return 200. Default: 60s
// Extensions
Extensions []Extension // Extensions to register with the app
// Config Auto-Discovery
// If ConfigManager is not provided, these options control auto-discovery
EnableConfigAutoDiscovery bool // Enable automatic config file discovery (default: true)
ConfigSearchPaths []string // Paths to search for config files (default: current directory)
ConfigBaseNames []string // Base config file names (default: ["config.yaml", "config.yml"])
ConfigLocalNames []string // Local config file names (default: ["config.local.yaml", "config.local.yml"])
EnableAppScopedConfig bool // Enable app-scoped config extraction for monorepos (default: true)
// Environment Variable Config Sources
// These options control how environment variables are loaded as config sources
EnableEnvConfig bool // Enable loading config from environment variables (default: true)
EnvPrefix string // Prefix for environment variables (default: app name uppercase, e.g., "MYAPP_")
EnvSeparator string // Separator for nested keys in env vars (default: "_")
EnvOverridesFile bool // Whether env vars override file config values (default: true)
// Database / Migration
DisableMigrations bool // When true, skip auto-migrations on serve (default: false). Also settable via .forge.yaml database.disable_migrations.
}
// DefaultAppConfig returns a default application configuration.
func DefaultAppConfig() AppConfig {
// Get proper default health config with all fields set
healthConfig := DefaultHealthConfig()
healthConfig.Intervals.Check = 30 * time.Second
healthConfig.Intervals.Report = 60 * time.Second
healthConfig.Features.AutoDiscovery = true
healthConfig.Performance.MaxConcurrentChecks = 10
healthConfig.Performance.DefaultTimeout = 5 * time.Second
healthConfig.Features.Aggregation = true
healthConfig.Performance.HistorySize = 100
return AppConfig{
Name: "forge-app",
Version: "1.0.0",
Description: "Forge Application",
Environment: "development",
HTTPAddress: ":8080",
HTTPTimeout: 30 * time.Second,
ShutdownTimeout: 30 * time.Second,
ShutdownSignals: nil, // Will use default SIGINT, SIGTERM
RouterOptions: nil,
MetricsConfig: DefaultMetricsConfig(),
HealthConfig: healthConfig,
HealthGracePeriod: 60 * time.Second,
EnableConfigAutoDiscovery: true,
EnableAppScopedConfig: true,
ConfigBaseNames: []string{"config.yaml", "config.yml"},
ConfigLocalNames: []string{"config.local.yaml", "config.local.yml"},
// Environment variable source defaults
EnableEnvConfig: true, // Enabled by default
EnvSeparator: "_", // Standard separator
EnvOverridesFile: true, // Env takes precedence over files by default
}
}
// AppOption is a functional option for AppConfig.
type AppOption func(*AppConfig)
// WithConfig replaces the entire config.
func WithConfig(config AppConfig) AppOption {
return func(c *AppConfig) {
*c = config
}
}
// WithAppName sets the application name.
func WithAppName(name string) AppOption {
return func(c *AppConfig) {
c.Name = name
}
}
// WithAppVersion sets the application version.
func WithAppVersion(version string) AppOption {
return func(c *AppConfig) {
c.Version = version
}
}
// WithAppDescription sets the application description.
func WithAppDescription(description string) AppOption {
return func(c *AppConfig) {
c.Description = description
}
}
// WithAppEnvironment sets the application environment.
func WithAppEnvironment(environment string) AppOption {
return func(c *AppConfig) {
c.Environment = environment
}
}
// WithAppConfigManager sets the config manager.
func WithAppConfigManager(configManager ConfigManager) AppOption {
return func(c *AppConfig) {
c.ConfigManager = configManager
}
}
// WithAppMetrics sets the metrics provider.
func WithAppMetrics(metrics Metrics) AppOption {
return func(c *AppConfig) {
c.Metrics = metrics
}
}
// WithAppLogger sets the logger.
func WithAppLogger(logger Logger) AppOption {
return func(c *AppConfig) {
c.Logger = logger
}
}
// WithAppRouterOptions sets the router options.
func WithAppRouterOptions(opts ...RouterOption) AppOption {
return func(c *AppConfig) {
c.RouterOptions = opts
}
}
// WithAppMetricsConfig sets the metrics configuration.
func WithAppMetricsConfig(config MetricsConfig) AppOption {
return func(c *AppConfig) {
c.MetricsConfig = config
}
}
// WithAppHealthConfig sets the health configuration.
func WithAppHealthConfig(config HealthConfig) AppOption {
return func(c *AppConfig) {
c.HealthConfig = config
}
}
// WithAppErrorHandler sets the error handler.
func WithAppErrorHandler(handler ErrorHandler) AppOption {
return func(c *AppConfig) {
c.ErrorHandler = handler
}
}
// WithHTTPAddress sets the HTTP address.
func WithHTTPAddress(address string) AppOption {
return func(c *AppConfig) {
c.HTTPAddress = address
}
}
// WithHTTPTimeout sets the HTTP timeout.
func WithHTTPTimeout(timeout time.Duration) AppOption {
return func(c *AppConfig) {
c.HTTPTimeout = timeout
}
}
// WithShutdownTimeout sets the shutdown timeout.
func WithShutdownTimeout(timeout time.Duration) AppOption {
return func(c *AppConfig) {
c.ShutdownTimeout = timeout
}
}
// WithShutdownSignals sets the shutdown signals.
func WithShutdownSignals(signals ...os.Signal) AppOption {
return func(c *AppConfig) {
c.ShutdownSignals = signals
}
}
// WithExtensions sets the extensions.
func WithExtensions(extensions ...Extension) AppOption {
return func(c *AppConfig) {
c.Extensions = extensions
}
}
// WithEnableConfigAutoDiscovery enables or disables config auto-discovery.
func WithEnableConfigAutoDiscovery(enabled bool) AppOption {
return func(c *AppConfig) {
c.EnableConfigAutoDiscovery = enabled
}
}
// WithConfigSearchPaths sets the config search paths.
func WithConfigSearchPaths(paths ...string) AppOption {
return func(c *AppConfig) {
c.ConfigSearchPaths = paths
}
}
// WithConfigBaseNames sets the config base names.
func WithConfigBaseNames(names ...string) AppOption {
return func(c *AppConfig) {
c.ConfigBaseNames = names
}
}
// WithConfigLocalNames sets the config local names.
func WithConfigLocalNames(names ...string) AppOption {
return func(c *AppConfig) {
c.ConfigLocalNames = names
}
}
// WithEnableAppScopedConfig enables or disables app-scoped config.
func WithEnableAppScopedConfig(enabled bool) AppOption {
return func(c *AppConfig) {
c.EnableAppScopedConfig = enabled
}
}
// WithEnableEnvConfig enables or disables environment variable config source.
func WithEnableEnvConfig(enabled bool) AppOption {
return func(c *AppConfig) {
c.EnableEnvConfig = enabled
}
}
// WithEnvPrefix sets the prefix for environment variables.
// If not set, defaults to the app name in uppercase with trailing underscore.
func WithEnvPrefix(prefix string) AppOption {
return func(c *AppConfig) {
c.EnvPrefix = prefix
}
}
// WithEnvSeparator sets the separator for nested keys in environment variables.
// Default is "_".
func WithEnvSeparator(separator string) AppOption {
return func(c *AppConfig) {
c.EnvSeparator = separator
}
}
// WithEnvOverridesFile controls whether environment variables override file config values.
// Default is true (env vars take precedence over file config).
func WithEnvOverridesFile(override bool) AppOption {
return func(c *AppConfig) {
c.EnvOverridesFile = override
}
}
// WithDisableMigrations disables auto-migrations on serve.
// This can also be set via .forge.yaml under database.disable_migrations.
func WithDisableMigrations() AppOption {
return func(c *AppConfig) { c.DisableMigrations = true }
}
// WithPprof enables pprof profiling endpoints.
// Endpoints are registered at /_/debug/pprof by default.
// Only enable in development or staging — never in production.
func WithPprof() AppOption {
return func(c *AppConfig) { c.EnablePprof = true }
}
// WithPprofPrefix sets a custom URL prefix for pprof endpoints.
// Implies WithPprof(). Default is "/_/debug/pprof".
func WithPprofPrefix(prefix string) AppOption {
return func(c *AppConfig) {
c.EnablePprof = true
c.PprofPrefix = prefix
}
}
// NewApp creates a new Forge application.
func NewApp(config AppConfig) App {
return newApp(config)
}
// NewWithConfig creates a new Forge application with a complete config.
func NewWithConfig(config AppConfig) App {
return newApp(config)
}
// New creates a new Forge application with variadic options.
func New(opts ...AppOption) App {
config := DefaultAppConfig()
for _, opt := range opts {
opt(&config)
}
return newApp(config)
}
// AppInfo represents application information returned by /_/info endpoint.
type AppInfo struct {
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
Environment string `json:"environment"`
StartTime time.Time `json:"start_time"`
Uptime time.Duration `json:"uptime"`
GoVersion string `json:"go_version"`
Services []string `json:"services"`
Routes int `json:"routes"`
Extensions []ExtensionInfo `json:"extensions,omitempty"`
}