-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathextension_template.go.tmpl
More file actions
115 lines (94 loc) · 3.53 KB
/
extension_template.go.tmpl
File metadata and controls
115 lines (94 loc) · 3.53 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
package {{.PackageName}}
import (
"context"
"fmt"
"github.com/xraph/forge"
)
// Extension implements forge.Extension for {{.Name}}.
// The extension is a lightweight facade that loads config and registers services.
// Service lifecycle is managed by Vessel, not by the extension.
type Extension struct {
*forge.BaseExtension
config Config
// No service instance storage - Vessel manages services
}
// NewExtension creates a new {{.Name}} extension with functional options.
func NewExtension(opts ...ConfigOption) forge.Extension {
config := DefaultConfig()
for _, opt := range opts {
opt(&config)
}
base := forge.NewBaseExtension("{{.ExtensionName}}", "{{.Version}}", "{{.Description}}")
return &Extension{
BaseExtension: base,
config: config,
}
}
// NewExtensionWithConfig creates a new {{.Name}} extension with a complete config.
func NewExtensionWithConfig(config Config) forge.Extension {
return NewExtension(WithConfig(config))
}
// Register registers the extension with the application.
// This method loads configuration and registers service constructors.
func (e *Extension) Register(app forge.App) error {
// Call base registration (sets logger, metrics, app)
if err := e.BaseExtension.Register(app); err != nil {
return err
}
// Load configuration
programmaticConfig := e.config
finalConfig := DefaultConfig()
if err := e.LoadConfig("{{.ExtensionName}}", &finalConfig, programmaticConfig, DefaultConfig(), programmaticConfig.RequireConfig); err != nil {
if programmaticConfig.RequireConfig {
return fmt.Errorf("{{.Name}}: failed to load required config: %w", err)
}
e.Logger().Warn("{{.Name}}: using default/programmatic config",
forge.F("error", err.Error()),
)
}
e.config = finalConfig
// Validate configuration
if err := e.config.Validate(); err != nil {
return fmt.Errorf("{{.Name}} config validation failed: %w", err)
}
// Register service constructor with Vessel - config captured in closure
// Vessel will manage the service lifecycle (Start/Stop/Health)
if err := e.RegisterConstructor(func(logger forge.Logger, metrics forge.Metrics) (*{{.ServiceName}}, error) {
return New{{.ServiceName}}(finalConfig, logger, metrics)
}); err != nil {
return fmt.Errorf("failed to register {{.Name}} service: %w", err)
}
// Register backward-compatible string key
if err := forge.RegisterSingleton(app.Container(), "{{.ServiceKey}}", func(c forge.Container) ({{.InterfaceName}}, error) {
return forge.InjectType[*{{.ServiceName}}](c)
}); err != nil {
return fmt.Errorf("failed to register {{.Name}} interface: %w", err)
}
e.Logger().Info("{{.Name}} extension registered",
forge.F("version", e.Version()),
)
return nil
}
// Start marks the extension as started.
// The actual service is started by Vessel calling {{.ServiceName}}.Start().
func (e *Extension) Start(ctx context.Context) error {
e.MarkStarted()
return nil
}
// Stop marks the extension as stopped.
// The actual service is stopped by Vessel calling {{.ServiceName}}.Stop().
func (e *Extension) Stop(ctx context.Context) error {
e.MarkStopped()
return nil
}
// Health checks the extension health.
// Service health is managed by Vessel through {{.ServiceName}}.Health().
func (e *Extension) Health(ctx context.Context) error {
// Optional: aggregate or check service health if needed
return nil
}
// Dependencies returns the names of extensions this extension depends on.
// Forge will ensure dependencies are started before this extension.
func (e *Extension) Dependencies() []string {
return []string{} // Add dependency names if needed
}