Service Discovery

Query, filter, and batch-register services in the container

Vessel provides service discovery APIs for querying registered services by lifecycle, group, metadata, or started status. It also supports batch registration for reducing boilerplate.

Querying Services

Query accepts a ServiceQuery struct and returns []ServiceInfo for all matching services.

import "github.com/xraph/vessel"

// Find all singleton services that have been started
started := true
results := vessel.Query(c, vessel.ServiceQuery{
    Lifecycle: "singleton",
    Started:   &started,
})

for _, info := range results {
    fmt.Printf("%s: lifecycle=%s started=%v\n", info.Name, info.Lifecycle, info.Started)
}

ServiceQuery Fields

FieldTypeDescription
LifecyclestringFilter by lifecycle: "singleton", "transient", "scoped". Empty matches all.
GroupstringFilter by service group name. Empty matches all.
Metadatamap[string]stringAll specified key-value pairs must match.
Started*boolFilter by started status. nil matches all.

QueryNames

When you only need service names (more efficient than full Query):

names := vessel.QueryNames(c, vessel.ServiceQuery{
    Group: "api-handlers",
})
// names is []string

Convenience Finders

// All services in a group
apiHandlers := vessel.FindByGroup(c, "api-handlers")

// All singletons
singletons := vessel.FindByLifecycle(c, "singleton")

// All started services
running := vessel.FindStarted(c)

// All services not yet started
pending := vessel.FindNotStarted(c)

Listing and Inspecting

The container itself provides lower-level inspection:

// List all registered service names
names := c.Services()

// Inspect a specific service
info := c.Inspect("database")
fmt.Printf("Name: %s\n", info.Name)
fmt.Printf("Lifecycle: %s\n", info.Lifecycle)
fmt.Printf("Started: %v\n", info.Started)
fmt.Printf("Metadata: %v\n", info.Metadata)

// Check existence
if c.Has("cache") {
    fmt.Println("Cache is registered")
}

// Check started status
if c.IsStarted("database") {
    fmt.Println("Database is running")
}

Batch Registration

Register multiple services in a single call to reduce boilerplate.

Untyped Batch

err := vessel.RegisterServices(c,
    vessel.Service("database", NewDatabase, vessel.Singleton()),
    vessel.Service("cache", NewCache, vessel.Singleton()),
    vessel.Service("logger", NewLogger, vessel.Singleton()),
)

Service creates a ServiceRegistration with a name, factory, and options. RegisterServices registers them all, stopping at the first error.

Typed Batch

When all services share the same type:

err := vessel.RegisterTypedServices(c,
    vessel.TypedService("primaryDB", NewPrimaryDB, vessel.Singleton()),
    vessel.TypedService("replicaDB", NewReplicaDB, vessel.Singleton()),
)

Keyed Batch

With typed service keys:

var (
    PrimaryDBKey = vessel.NewServiceKey[*Database]("primaryDB")
    ReplicaDBKey = vessel.NewServiceKey[*Database]("replicaDB")
)

err := vessel.RegisterKeyedServices(c,
    vessel.KeyedService(PrimaryDBKey, NewPrimaryDB, vessel.Singleton()),
    vessel.KeyedService(ReplicaDBKey, NewReplicaDB, vessel.Singleton()),
)

Registration Options

All registration methods accept RegisterOption values:

OptionEffect
vessel.Singleton()One instance for the app lifetime (default)
vessel.Transient()New instance on each resolve
vessel.Scoped()One instance per scope
vessel.WithDependencies("a", "b")Declare explicit dependencies for startup ordering
vessel.WithGroup("name")Add service to a named group
vessel.WithDIMetadata("key", "value")Attach diagnostic metadata

How is this guide?

On this page