Entry Handlers
Entry Handlers
Section titled “Entry Handlers”Entry handlers process registry entries by kind. When entries are added, updated, or deleted, the registry dispatches events to matching handlers.
How It Works
Section titled “How It Works”The registry maintains a map of kind patterns to handlers. When an entry changes:
- Registry emits event (
entry.create,entry.update,entry.delete) - Handler registry matches entry kind against registered patterns
- Matching handlers receive the entry
- Handlers process or reject the entry
Kind Patterns
Section titled “Kind Patterns”Handlers subscribe using patterns:
| Pattern | Matches |
|---|---|
http.service | Exact match only |
http.* | http.service, http.router, http.endpoint |
function.** | function.lua, function.lua.bc |
Entry Listener Interface
Section titled “Entry Listener Interface”Handlers implement registry.EntryListener:
type EntryListener interface { Add(ctx context.Context, entry Entry) error Update(ctx context.Context, entry Entry) error Delete(ctx context.Context, entry Entry) error}Returning an error from Add rejects the entry.
Listener vs Observer
Section titled “Listener vs Observer”| Type | Purpose | Can Reject |
|---|---|---|
| Listener | Primary handler | Yes |
| Observer | Secondary handler (logging, metrics) | No |
handlers.RegisterListener("http.*", httpManager)handlers.RegisterObserver("function.*", metricsCollector)Registering Handlers
Section titled “Registering Handlers”Register handlers during boot:
func MyService() boot.Component { return boot.New(boot.P{ Name: "myservice", DependsOn: []boot.Name{core.RegistryName}, Load: func(ctx context.Context) (context.Context, error) { handlers := bootpkg.GetHandlerRegistry(ctx) handlers.RegisterListener("myservice.*", manager) return ctx, nil }, })}Decoding Entry Data
Section titled “Decoding Entry Data”Use entry.DecodeEntryConfig from internal/entry to unmarshal entry data. This helper lives under internal/, so it is only importable from inside the runtime module; out-of-tree extensions must copy the pattern or use the transcoder directly:
func (m *Manager) Add(ctx context.Context, ent registry.Entry) error { cfg, err := entry.DecodeEntryConfig[ComponentConfig](ctx, m.dtt, ent) if err != nil { return err } // Process cfg... return nil}The decoder:
- Unmarshals
entry.Datainto your config struct - Populates
IDandMetafrom the entry - Calls
InitDefaults()if implemented - Calls
Validate()if implemented
Config Structure
Section titled “Config Structure”Entry configs typically include:
type ComponentConfig struct { ID registry.ID `json:"id"` Meta attrs.Bag `json:"meta"` Name string `json:"name"` Timeout int `json:"timeout,omitempty"`}
func (c *ComponentConfig) InitDefaults() { if c.Timeout == 0 { c.Timeout = 30 }}
func (c *ComponentConfig) Validate() error { if c.Name == "" { return fmt.Errorf("name is required") } return nil}Transaction Support
Section titled “Transaction Support”For atomic operations across multiple entries, implement TransactionListener:
type TransactionListener interface { Begin(ctx context.Context) error Commit(ctx context.Context) error Discard(ctx context.Context) error}The registry calls Begin before processing a batch, then Commit on success or Discard on failure.
See Also
Section titled “See Also”- Registry - Entry storage
- Architecture - Boot sequence