do

package module
v2.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 17, 2025 License: MIT Imports: 19 Imported by: 0

README ΒΆ

do - Dependency Injection

tag Go Version GoDoc Build Status Go report Coverage License

βš™οΈ A dependency injection toolkit based on Go 1.18+ Generics.

This library implements the Dependency Injection design pattern. It may replace the fantastic uber/dig package. samber/do uses Go 1.18+ generics and therefore offers a type‑safe API.

image

See also:

  • samber/ro: Reactive Programming for Go: declarative and composable API for event-driven applications
  • samber/lo: A Lodash-style Go library based on Go 1.18+ Generics
  • samber/mo: Monads based on Go 1.18+ Generics (Option, Result, Either...)

πŸ’– Support This Project

I’m going all-in on open-source for the coming months.
Help sustain development: Become an individual sponsor or join as a corporate sponsor.


Why this name?

I love the short name for such a utility library. This name is the sum of DI and Go and no Go package uses this name.

πŸ’‘ Features

  • πŸ“’ Service registration
    • Register by type
    • Register by name
    • Register multiple services from a package at once
  • πŸͺƒ Service invocation
    • Eager loading
    • Lazy loading
    • Transient loading
    • Tag-based invocation
    • Circular dependency detection
  • πŸ§™β€β™‚οΈ Service aliasing
    • Implicit (provide struct, invoke interface)
    • Explicit (provide struct, bind interface, invoke interface)
  • πŸ” Service lifecycle
    • Health check
    • Graceful unload (shutdown)
    • Dependency-aware parallel shutdown
    • Lifecycle hooks
  • πŸ“¦ Scope (a.k.a module) tree
    • Visibility control
    • Dependency grouping
  • πŸ“€ Container
    • Dependency graph resolution and visualization
    • Default container
    • Container cloning
    • Service override
  • πŸ§ͺ Debugging & introspection
    • Explain APIs: scope tree and service dependencies
    • Web UI & HTTP middleware (std, Gin, Fiber, Echo, Chi)
  • 🌈 Lightweight, no dependencies
  • πŸ”… No code generation
  • 😷 Type‑safe API

πŸš€ Install

# v2 (latest)
go get github.com/samber/do/v2@latest

# v1
go get github.com/samber/[email protected]

This library is v2 and follows SemVer strictly.

No breaking changes will be made to exported APIs before v3.0.0.

This library has no dependencies except the Go std lib.

πŸ”₯ Migration from v1 to v2

Documentation here

🀠 Documentation

🎬 Project boilerplate

🀝 Contributing

Don't hesitate ;)

# Install some dev dependencies
make tools

# Run tests
make test
# or
make watch-test

πŸ‘€ Contributors

Contributors

πŸ’« Show your support

Give a ⭐️ if this project helped you!

GitHub Sponsors

πŸ“ License

Copyright Β© 2022 Samuel Berthe.

This project is MIT licensed.

Documentation ΒΆ

Index ΒΆ

Examples ΒΆ

Constants ΒΆ

View Source
const DefaultRootScopeName = "[root]"

DefaultRootScopeName is the default name for the root scope.

View Source
const DefaultStructTagKey = "do"

DefaultStructTagKey is the default tag key used for struct field injection. When using struct injection, fields can be tagged with `do:""` or `do:"service-name"` to specify which service should be injected.

Variables ΒΆ

View Source
var (
	//nolint:revive
	ErrServiceNotFound    = errors.New("DI: could not find service")
	ErrServiceNotMatch    = errors.New("DI: could not find service satisfying interface")
	ErrCircularDependency = errors.New("DI: circular dependency detected")
	ErrHealthCheckTimeout = errors.New("DI: health check timeout")
)
View Source
var DefaultRootScope = New()

DefaultRootScope is a global instance of the root scope that can be used for simple dependency injection scenarios without creating a custom scope.

View Source
var MaxInvocationFrames uint32 = 100

MaxInvocationFrames defines the maximum number of stack frames to capture when tracking service invocations for debugging and observability purposes.

Functions ΒΆ

func As ΒΆ

func As[Initial any, Alias any](i Injector) error

As declares an alias for a service, allowing it to be retrieved using a different type. This function creates a type alias where the Alias type can be used to retrieve the Initial service. The alias is automatically named using the type name of Alias.

Parameters:

  • i: The injector to register the alias in

Returns an error if the alias cannot be created (e.g., type incompatibility or missing service).

Play: https://go.dev/play/p/T5zKBRZaZhj

Example:

// Register a concrete service
do.Provide(injector, func(i do.Injector) (*PostgresqlDatabase, error) {
    return &PostgresqlDatabase{}, nil
})

// Create an alias so it can be retrieved as an interface
do.As[*PostgresqlDatabase, Database](injector)

// Now both work:
db := do.MustInvoke[*PostgresqlDatabase](injector)
db := do.MustInvoke[Database](injector)
Example ΒΆ
injector := New()

Provide(injector, aliasMyServiceProvider)
err := As[*myService, IMyService](injector)

fmt.Println(err)

// Now both work:
service1, _ := Invoke[*myService](injector)
service2, _ := Invoke[IMyService](injector)

fmt.Println(service1.GetName())
fmt.Println(service2.GetName())
Output:

<nil>
alias-test-service
alias-test-service

func AsNamed ΒΆ

func AsNamed[Initial any, Alias any](i Injector, initial string, alias string) error

AsNamed declares a named alias for a named service. This function allows you to create aliases with custom names for both the initial service and the alias.

Parameters:

  • i: The injector to register the alias in
  • initial: The name of the existing service to alias
  • alias: The name for the new alias service

Returns an error if the alias cannot be created (e.g., type incompatibility or missing service).

Play: https://go.dev/play/p/h1R5rxKizwR

Example:

// Register a service with a custom name
do.ProvideNamed(injector, "my-db", func(i do.Injector) (*PostgresqlDatabase, error) {
    return &PostgresqlDatabase{}, nil
})

// Create an alias with custom names
do.AsNamed[*PostgresqlDatabase, Database](injector, "my-db", "db-interface")

// Retrieve using the alias name
db := do.MustInvokeNamed[Database](injector, "db-interface")
Example ΒΆ
injector := New()

ProvideNamed(injector, "my-service", aliasMyServiceProvider)
err := AsNamed[*myService, IMyService](injector, "my-service", "my-interface")

fmt.Println(err)

// Retrieve using the alias name
service, _ := InvokeNamed[IMyService](injector, "my-interface")
fmt.Println(service.GetName())
Output:

<nil>
alias-test-service

func Bind ΒΆ

func Bind[Initial any, Alias any]() func(Injector)

Bind creates a function that creates a type alias between two types. This function is a convenience wrapper for creating service binding functions that can be used in packages.

Parameters:

  • Initial: The original type to bind from
  • Alias: The type to bind to (must be implemented by Initial)

Returns a function that creates the type alias when executed. Panics if the binding cannot be created.

Play: https://go.dev/play/p/j69I52whJr2

Example:

// Global to a package
var Package = do.Package(
	do.Bind[*Database, DatabaseInterface]()
)

func BindNamed ΒΆ

func BindNamed[Initial any, Alias any](initial string, alias string) func(Injector)

BindNamed creates a function that creates a named type alias between two types. This function is a convenience wrapper for creating named service binding functions that can be used in packages.

Parameters:

  • initial: The name of the original service
  • alias: The name for the alias service
  • Initial: The original type to bind from
  • Alias: The type to bind to (must be implemented by Initial)

Returns a function that creates the named type alias when executed. Panics if the binding cannot be created.

Play: https://go.dev/play/p/m2gW7s9_qgq

Example:

// Global to a package
var Package = do.Package(
	do.BindNamed[*Database, DatabaseInterface]("main-db", "db-interface")
)

func Eager ΒΆ

func Eager[T any](value T) func(Injector)

Eager creates a function that registers an eager service using the default service name. This function is a convenience wrapper for creating eager service registration functions that can be used in packages. The service value is provided directly.

Parameters:

  • value: The service instance to register eagerly

Returns a function that registers the service as eager when executed.

Play: https://go.dev/play/p/M6-wd1qt-GZ

Example:

// Global to a package
var Package = do.Package(
	do.Eager[*Config](&Config{Port: 8080})
)

func EagerNamed ΒΆ

func EagerNamed[T any](serviceName string, value T) func(Injector)

EagerNamed creates a function that registers an eager service with a custom name. This function is a convenience wrapper for creating named eager service registration functions that can be used in packages. The service value is provided directly.

Parameters:

  • serviceName: The custom name for the service
  • value: The service instance to register eagerly

Returns a function that registers the service as eager with the specified name when executed.

Play: https://go.dev/play/p/pvByI4EkFEJ

Example:

// Global to a package
var Package = do.Package(
	do.EagerNamed[*Config]("app-config", &Config{Port: 8080})
)

func HealthCheck ΒΆ

func HealthCheck[T any](i Injector) error

HealthCheck returns a service status, using type inference to determine the service name. This function performs a health check on a service by inferring its name from the type T. The service must implement either Healthchecker or HealthcheckerWithContext interface.

Parameters:

  • i: The injector containing the service

Returns an error if the health check fails, or nil if the service is healthy.

Play: https://go.dev/play/p/dg1OzQCFJVm

Example:

err := do.HealthCheck[*Database](injector)
if err != nil {
    log.Printf("Database health check failed: %v", err)
}
Example ΒΆ
injector := New()

Provide(injector, lifecycleTestServiceProvider)
_, _ = Invoke[*lifecycleTestService](injector)

err := HealthCheck[*lifecycleTestService](injector)
fmt.Println(err)
Output:

<nil>

func HealthCheckNamed ΒΆ

func HealthCheckNamed(i Injector, name string) error

HealthCheckNamed returns a service status for a named service. This function performs a health check on a service with the specified name. The service must implement either Healthchecker or HealthcheckerWithContext interface.

Parameters:

  • i: The injector containing the service
  • name: The name of the service to health check

Returns an error if the health check fails, or nil if the service is healthy.

Play: https://go.dev/play/p/jhaaEIPad_d

Example:

err := do.HealthCheckNamed(injector, "main-database")
if err != nil {
    log.Printf("Main database health check failed: %v", err)
}
Example ΒΆ
injector := New()

ProvideNamed(injector, "main-database", lifecycleTestServiceProvider)
_, _ = InvokeNamed[*lifecycleTestService](injector, "main-database")

err := HealthCheckNamed(injector, "main-database")
fmt.Println(err)
Output:

<nil>

func HealthCheckNamedWithContext ΒΆ

func HealthCheckNamedWithContext(ctx context.Context, i Injector, name string) error

HealthCheckNamedWithContext returns a service status for a named service with context support. This function performs a health check on a service with the specified name and context support for timeout and cancellation. The service must implement either Healthchecker or HealthcheckerWithContext interface.

Parameters:

  • ctx: Context for cancellation and timeout control
  • i: The injector containing the service
  • name: The name of the service to health check

Returns an error if the health check fails, or nil if the service is healthy.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

err := do.HealthCheckNamedWithContext(ctx, injector, "main-database")
if err != nil {
    log.Printf("Main database health check failed: %v", err)
}
Example ΒΆ
injector := New()

ProvideNamed(injector, "main-database", lifecycleTestServiceProvider)
_, _ = InvokeNamed[*lifecycleTestService](injector, "main-database")

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

err := HealthCheckNamedWithContext(ctx, injector, "main-database")
fmt.Println(err)
Output:

<nil>

func HealthCheckWithContext ΒΆ

func HealthCheckWithContext[T any](ctx context.Context, i Injector) error

HealthCheckWithContext returns a service status, using type inference to determine the service name. This function performs a health check on a service with context support for timeout and cancellation. The service must implement either Healthchecker or HealthcheckerWithContext interface.

Parameters:

  • ctx: Context for cancellation and timeout control
  • i: The injector containing the service

Returns an error if the health check fails, or nil if the service is healthy.

Play: https://go.dev/play/p/jhaaEIPad_d

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

err := do.HealthCheckWithContext[*Database](ctx, injector)
if err != nil {
    log.Printf("Database health check failed: %v", err)
}
Example ΒΆ
injector := New()

Provide(injector, lifecycleTestServiceProvider)
_, _ = Invoke[*lifecycleTestService](injector)

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

err := HealthCheckWithContext[*lifecycleTestService](ctx, injector)
fmt.Println(err)
Output:

<nil>

func Invoke ΒΆ

func Invoke[T any](i Injector) (T, error)

Invoke retrieves and instantiates a service from the DI container using type inference. The service will be created if it hasn't been instantiated yet (for lazy services).

Play: https://go.dev/play/p/4JutUJ5Rqau

Example:

service, err := do.Invoke[*MyService](injector)
Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

Provide(injector, func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
service, err := Invoke[*exampleService](injector)

fmt.Println(err)
fmt.Println(service.Name)
Output:

<nil>
test-service

func InvokeAs ΒΆ

func InvokeAs[T any](i Injector) (T, error)

InvokeAs invokes a service in the DI container by finding the first service that matches the provided type or interface. This function searches through all registered services to find one that can be cast to the requested type T. It's useful when you want to retrieve a service by interface without explicitly creating aliases.

Parameters:

  • i: The injector to search for the service

Returns the service instance and any error that occurred during invocation.

Play: https://go.dev/play/p/1uXvNenBbgk

Example:

// Register a concrete service
do.Provide(injector, func(i do.Injector) (*PostgresqlDatabase, error) {
    return &PostgresqlDatabase{}, nil
})

// Retrieve by interface
db, err := do.InvokeAs[Database](injector)
Example ΒΆ
injector := New()

Provide(injector, aliasMyServiceProvider)
service, err := InvokeAs[IMyService](injector)

fmt.Println(err)
fmt.Println(service.GetName())
Output:

<nil>
alias-test-service

func InvokeNamed ΒΆ

func InvokeNamed[T any](i Injector, name string) (T, error)

InvokeNamed retrieves and instantiates a named service from the DI container. This allows you to retrieve specific named services when multiple services of the same type are registered.

Play: https://go.dev/play/p/9JuTQhLGIlh

Example:

// Register multiple databases
do.ProvideNamed(injector, "main-db", func(i do.Injector) (*Database, error) {
    return &Database{URL: "postgres://main.acme.dev:5432/db"}, nil
})
do.ProvideNamed(injector, "backup-db", func(i do.Injector) (*Database, error) {
    return &Database{URL: "postgres://backup.acme.dev:5432/db"}, nil
})

// Retrieve specific database
mainDB, err := do.InvokeNamed[*Database](injector, "main-db")
backupDB, err := do.InvokeNamed[*Database](injector, "backup-db")
Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

ProvideNamed(injector, "my-service", func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
service, err := InvokeNamed[*exampleService](injector, "my-service")

fmt.Println(err)
fmt.Println(service.Name)
Output:

<nil>
test-service

func InvokeStruct ΒΆ

func InvokeStruct[T any](i Injector) (T, error)

InvokeStruct invokes services located in struct properties. The struct fields must be tagged with `do:""` or `do:"name"`, where `name` is the service name in the DI container. If the service is not found in the DI container, an error is returned. If the service is found but not assignable to the struct field, an error is returned.

Play: https://go.dev/play/p/I3_Rznkprpj

Example:

type App struct {
    Database *Database `do:""`
    Logger   *Logger   `do:"app-logger"`
    Config   *Config   `do:""`
}

// Register services
do.Provide(injector, func(i do.Injector) (*Database, error) {
    return &Database{}, nil
})
do.ProvideNamed(injector, "app-logger", func(i do.Injector) (*Logger, error) {
    return &Logger{}, nil
})
do.Provide(injector, func(i do.Injector) (*Config, error) {
    return &Config{}, nil
})

// Invoke struct with injected services
app, err := do.InvokeStruct[App](injector)
Example ΒΆ
type exampleService struct {
	Name string
}
type exampleStructService struct {
	Service *exampleService `do:""`
}

injector := New()

Provide(injector, func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
service, err := InvokeStruct[exampleStructService](injector)

fmt.Println(err)
fmt.Println(service.Service.Name)
Output:

<nil>
test-service
Example (Named) ΒΆ
type exampleService struct {
	Name string
}
type exampleStructStruct struct {
	Service *exampleService `do:"my-service"`
}

injector := New()

ProvideNamed(injector, "my-service", func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
service, err := InvokeStruct[exampleStructStruct](injector)

fmt.Println(err)
fmt.Println(service.Service.Name)
Output:

<nil>
test-service

func Lazy ΒΆ

func Lazy[T any](p Provider[T]) func(Injector)

Lazy creates a function that registers a lazy service using the default service name. This function is a convenience wrapper for creating lazy service registration functions that can be used in packages.

Parameters:

  • p: The provider function that creates the service instance

Returns a function that registers the service as lazy when executed.

Play: https://go.dev/play/p/M6-wd1qt-GZ

Example:

// Global to a package
var Package = do.Package(
	do.Lazy[*Database](func(i do.Injector) (*Database, error) {
    	return &Database{}, nil
	}),
)

func LazyNamed ΒΆ

func LazyNamed[T any](serviceName string, p Provider[T]) func(Injector)

LazyNamed creates a function that registers a lazy service with a custom name. This function is a convenience wrapper for creating named lazy service registration functions that can be used in packages.

Parameters:

  • serviceName: The custom name for the service
  • p: The provider function that creates the service instance

Returns a function that registers the service as lazy with the specified name when executed.

Play: https://go.dev/play/p/xAs-exXR9Sz

Example:

// Global to a package
var Package = do.Package(
	do.LazyNamed[*Database]("main-db", func(i do.Injector) (*Database, error) {
    	return &Database{}, nil
	}),
)

func MustAs ΒΆ

func MustAs[Initial any, Alias any](i Injector)

MustAs declares an alias for a service and panics if an error occurs. This is a convenience function that wraps As and panics on error.

Parameters:

  • i: The injector to register the alias in

Panics if the alias cannot be created (e.g., type incompatibility or missing service).

Play: https://go.dev/play/p/_wGjnRJfwV8

Example:

do.MustAs[*PostgresqlDatabase, Database](injector)
Example ΒΆ
injector := New()

Provide(injector, aliasMyServiceProvider)
MustAs[*myService, IMyService](injector)

// Now both work:
service1 := MustInvoke[*myService](injector)
service2 := MustInvoke[IMyService](injector)

fmt.Println(service1.GetName())
fmt.Println(service2.GetName())
Output:

alias-test-service
alias-test-service

func MustAsNamed ΒΆ

func MustAsNamed[Initial any, Alias any](i Injector, initial string, alias string)

MustAsNamed declares a named alias for a named service and panics if an error occurs. This is a convenience function that wraps AsNamed and panics on error.

Parameters:

  • i: The injector to register the alias in
  • initial: The name of the existing service to alias
  • alias: The name for the new alias service

Panics if the alias cannot be created (e.g., type incompatibility or missing service).

Play: https://go.dev/play/p/8QI2XUm9yLH

Example:

do.MustAsNamed[*PostgresqlDatabase, Database](injector, "my-db", "db-interface")
Example ΒΆ
injector := New()

ProvideNamed(injector, "my-service", aliasMyServiceProvider)
MustAsNamed[*myService, IMyService](injector, "my-service", "my-interface")

// Retrieve using the alias name
service := MustInvokeNamed[IMyService](injector, "my-interface")
fmt.Println(service.GetName())
Output:

alias-test-service

func MustInvoke ΒΆ

func MustInvoke[T any](i Injector) T

MustInvoke retrieves and instantiates a service from the DI container using type inference. If the service cannot be retrieved or instantiated, it panics.

This function is useful when you're certain the service exists and want to avoid error handling in your code.

Play: https://go.dev/play/p/456pBhI36Q2

Example:

service := do.MustInvoke[*MyService](injector)
Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

Provide(injector, func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
service := MustInvoke[*exampleService](injector)

fmt.Println(service.Name)
Output:

test-service

func MustInvokeAs ΒΆ

func MustInvokeAs[T any](i Injector) T

MustInvokeAs invokes a service in the DI container by finding the first service that matches the provided type or interface. This function panics if an error occurs during invocation. It's useful when you want to retrieve a service by interface without explicitly creating aliases.

Parameters:

  • i: The injector to search for the service

Returns the service instance. Panics if the service cannot be found or invoked.

Play: https://go.dev/play/p/29gb2TJG4m5

Example:

// Register a concrete service
do.Provide(injector, func(i do.Injector) (*PostgresqlDatabase, error) {
    return &PostgresqlDatabase{}, nil
})

// Retrieve by interface
db := do.MustInvokeAs[Database](injector)
Example ΒΆ
injector := New()

Provide(injector, aliasMyServiceProvider)
service := MustInvokeAs[IMyService](injector)

fmt.Println(service.GetName())
Output:

alias-test-service

func MustInvokeNamed ΒΆ

func MustInvokeNamed[T any](i Injector, name string) T

MustInvokeNamed retrieves and instantiates a named service from the DI container. If the service cannot be retrieved or instantiated, it panics.

This function is useful when you're certain the named service exists and want to avoid error handling in your code.

Play: https://go.dev/play/p/456pBhI36Q2

Example:

service := do.MustInvokeNamed[*MyService](injector, "my-service")
Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

ProvideNamed(injector, "my-service", func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
service := MustInvokeNamed[*exampleService](injector, "my-service")

fmt.Println(service.Name)
Output:

test-service

func MustInvokeStruct ΒΆ

func MustInvokeStruct[T any](i Injector) T

MustInvokeStruct invokes services located in struct properties and panics on error. The struct fields must be tagged with `do:""` or `do:"name"`, where `name` is the service name in the DI container. If the service is not found in the DI container, it panics. If the service is found but not assignable to the struct field, it panics.

Play: https://go.dev/play/p/lRKqRT9TQVf

Example:

type App struct {
    Database *Database `do:""`
    Logger   *Logger   `do:"app-logger"`
    Config   *Config   `do:""`
}

// Register services
do.Provide(injector, func(i do.Injector) (*Database, error) {
    return &Database{}, nil
})
do.ProvideNamed(injector, "app-logger", func(i do.Injector) (*Logger, error) {
    return &Logger{}, nil
})
do.Provide(injector, func(i do.Injector) (*Config, error) {
    return &Config{}, nil
})

// Invoke struct with injected services (panics on error)
app := do.MustInvokeStruct[App](injector)
Example ΒΆ
type exampleService struct {
	Name string
}
type exampleStructService struct {
	Service *exampleService `do:""`
}

injector := New()

Provide(injector, func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
service := MustInvokeStruct[exampleStructService](injector)

fmt.Println(service.Service.Name)
Output:

test-service

func MustShutdown ΒΆ

func MustShutdown[T any](i Injector)

MustShutdown stops a service, using type inference to determine the service name. It panics on error. This function performs a graceful shutdown on a service by inferring its name from the type T. If the shutdown fails, this function will panic.

Parameters:

  • i: The injector containing the service

Panics if the shutdown fails.

Play: https://go.dev/play/p/cjKFvjZpeAV

Example:

do.MustShutdown[*Database](injector)
Example ΒΆ
injector := New()

Provide(injector, lifecycleTestServiceProvider)
_, _ = Invoke[*lifecycleTestService](injector)

// This will panic if shutdown fails
MustShutdown[*lifecycleTestService](injector)
fmt.Println("shutdown completed")
Output:

shutdown completed

func MustShutdownNamed ΒΆ

func MustShutdownNamed(i Injector, name string)

MustShutdownNamed stops a named service. It panics on error. This function performs a graceful shutdown on a service with the specified name. If the shutdown fails, this function will panic.

Parameters:

  • i: The injector containing the service
  • name: The name of the service to shutdown

Panics if the shutdown fails.

Play: https://go.dev/play/p/cjKFvjZpeAV

Example:

do.MustShutdownNamed(injector, "main-database")
Example ΒΆ
injector := New()

ProvideNamed(injector, "main-database", lifecycleTestServiceProvider)
_, _ = InvokeNamed[*lifecycleTestService](injector, "main-database")

// This will panic if shutdown fails
MustShutdownNamed(injector, "main-database")
fmt.Println("shutdown completed")
Output:

shutdown completed

func MustShutdownNamedWithContext ΒΆ

func MustShutdownNamedWithContext(ctx context.Context, i Injector, name string)

MustShutdownNamedWithContext stops a named service. It panics on error. This function performs a graceful shutdown on a service with the specified name and context support for timeout and cancellation. If the shutdown fails, this function will panic.

Parameters:

  • ctx: Context for cancellation and timeout control
  • i: The injector containing the service
  • name: The name of the service to shutdown

Panics if the shutdown fails.

Play: https://go.dev/play/p/cjKFvjZpeAV

Example:

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

do.MustShutdownNamedWithContext(ctx, injector, "main-database")
Example ΒΆ
injector := New()

ProvideNamed(injector, "main-database", lifecycleTestServiceProvider)
_, _ = InvokeNamed[*lifecycleTestService](injector, "main-database")

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// This will panic if shutdown fails
MustShutdownNamedWithContext(ctx, injector, "main-database")
fmt.Println("shutdown completed")
Output:

shutdown completed

func MustShutdownWithContext ΒΆ

func MustShutdownWithContext[T any](ctx context.Context, i Injector)

MustShutdownWithContext stops a service, using type inference to determine the service name. It panics on error. This function performs a graceful shutdown on a service with context support for timeout and cancellation. If the shutdown fails, this function will panic.

Parameters:

  • ctx: Context for cancellation and timeout control
  • i: The injector containing the service

Panics if the shutdown fails.

Play: https://go.dev/play/p/cjKFvjZpeAV

Example:

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

do.MustShutdownWithContext[*Database](ctx, injector)
Example ΒΆ
injector := New()

Provide(injector, lifecycleTestServiceProvider)
_, _ = Invoke[*lifecycleTestService](injector)

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// This will panic if shutdown fails
MustShutdownWithContext[*lifecycleTestService](ctx, injector)
fmt.Println("shutdown completed")
Output:

shutdown completed

func NameOf ΒΆ

func NameOf[T any]() string

NameOf returns the name of the service in the DI container. This is highly discouraged to use this function, as your code should not declare any dependency explicitly.

The function uses type inference to determine the service name based on the generic type parameter T.

Play: https://go.dev/play/p/g549GqBbj-n

Example:

serviceName := do.NameOf[*Database]()
Example ΒΆ
type exampleService struct {
	Name string
}

name := NameOf[*exampleService]()

fmt.Println(name)
Output:

*gitee.com/supos-community-edition/di/v2.exampleService

func Override ΒΆ

func Override[T any](i Injector, provider Provider[T])

Override replaces the service in the DI container, using type inference to determine the service name. Warning: this will not unload/shutdown the previously invoked service.

This function is useful for testing or when you need to replace a service that has already been registered. However, be cautious as it may lead to resource leaks if the original service was already instantiated.

Play: https://go.dev/play/p/g549GqBbj-n

Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

Provide(injector, func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
Override(injector, func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "overridden-service"}, nil
})
service, _ := Invoke[*exampleService](injector)

fmt.Println(service.Name)
Output:

overridden-service

func OverrideNamed ΒΆ

func OverrideNamed[T any](i Injector, name string, provider Provider[T])

OverrideNamed replaces the named service in the DI container. Warning: this will not unload/shutdown the previously invoked service.

This function allows you to replace a specific named service that has already been registered. Use with caution to avoid resource leaks.

Play: https://go.dev/play/p/-gNF1BUEB5Q

Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

ProvideNamed(injector, "my-service", func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
OverrideNamed(injector, "my-service", func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "overridden-named-service"}, nil
})
service, _ := InvokeNamed[*exampleService](injector, "my-service")

fmt.Println(service.Name)
Output:

overridden-named-service

func OverrideNamedTransient ΒΆ

func OverrideNamedTransient[T any](i Injector, name string, provider Provider[T])

OverrideNamedTransient replaces the named factory in the DI container. Warning: this will not unload/shutdown the previously invoked service.

This function allows you to replace a specific named transient service factory. Since transient services are recreated on each request, this is generally safer than overriding lazy or eager services.

Play: https://go.dev/play/p/_wYwBADbCaN

Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

ProvideNamed(injector, "my-service", func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
OverrideNamedTransient(injector, "my-service", func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "overridden-service"}, nil
})
service1, _ := InvokeNamed[*exampleService](injector, "my-service")
service2, _ := InvokeNamed[*exampleService](injector, "my-service")

fmt.Println(service1 != service2)
Output:

true

func OverrideNamedValue ΒΆ

func OverrideNamedValue[T any](i Injector, name string, value T)

OverrideNamedValue replaces the named value in the DI container. Warning: this will not unload/shutdown the previously invoked service.

This function allows you to replace a specific named value service. Use with caution to avoid resource leaks.

Play: https://go.dev/play/p/-gNF1BUEB5Q

Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

ProvideNamed(injector, "my-service", func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
OverrideNamedValue(injector, "my-service", &exampleService{Name: "overridden-named-value-service"})
service, _ := InvokeNamed[*exampleService](injector, "my-service")

fmt.Println(service.Name)
Output:

overridden-named-value-service

func OverrideTransient ΒΆ

func OverrideTransient[T any](i Injector, provider Provider[T])

OverrideTransient replaces the factory in the DI container, using type inference to determine the service name. Warning: this will not unload/shutdown the previously invoked service.

This function replaces an existing transient service factory with a new one. Since transient services are recreated on each request, this is generally safer than overriding lazy or eager services.

Play: https://go.dev/play/p/_wYwBADbCaN

Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

Provide(injector, func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
OverrideTransient(injector, func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "overridden-service"}, nil
})
service1, _ := Invoke[*exampleService](injector)
service2, _ := Invoke[*exampleService](injector)

fmt.Println(service1 != service2)
Output:

true

func OverrideValue ΒΆ

func OverrideValue[T any](i Injector, value T)

OverrideValue replaces the value in the DI container, using type inference to determine the service name. Warning: this will not unload/shutdown the previously invoked service.

This function replaces an existing value service with a new one. The old value will not be properly cleaned up if it was already instantiated.

Play: https://go.dev/play/p/-gNF1BUEB5Q

Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

Provide(injector, func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
OverrideValue(injector, &exampleService{Name: "overridden-value-service"})
service, _ := Invoke[*exampleService](injector)

fmt.Println(service.Name)
Output:

overridden-value-service

func Package ΒΆ

func Package(services ...func(i Injector)) func(Injector)

Package creates a function that executes multiple service registration functions. This function is used to group related service registrations into reusable packages that can be applied to any injector instance.

Parameters:

  • services: Variable number of service registration functions to execute

Returns a function that can be passed to New(), NewWithOpts(), or Scope() to register all services.

Play: https://go.dev/play/p/kmf8aOVyj96

Example:

	 // pkg/database/package.go
		// Create a global `Package` variable
		var Package = do.Package(
		    do.Lazy[*Database](func(i do.Injector) (*Database, error) {
		        return &Database{}, nil
		    }),
		    do.Lazy[*ConnectionPool](func(i do.Injector) (*ConnectionPool, error) {
		        return &ConnectionPool{}, nil
		    }),
         ...
		)

	 // main.go
		// Apply the package to an injector
		injector := do.New(database.Package)

func Provide ΒΆ

func Provide[T any](i Injector, provider Provider[T])

Provide registers a service in the DI container, using type inference. The service will be lazily instantiated when first requested.

Play: https://go.dev/play/p/4JutUJ5Rqau

Example:

do.Provide(injector, func(i do.Injector) (*MyService, error) {
    return &MyService{...}, nil
})
Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

Provide(injector, func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
service, err := Invoke[*exampleService](injector)

fmt.Println(err)
fmt.Println(service.Name)
Output:

<nil>
test-service

func ProvideNamed ΒΆ

func ProvideNamed[T any](i Injector, name string, provider Provider[T])

ProvideNamed registers a named service in the DI container. This allows you to register multiple services of the same type with different names for disambiguation.

The service will be lazily instantiated when first requested.

Play: https://go.dev/play/p/9JuTQhLGIlh

Example:

do.ProvideNamed(injector, "main-db", func(i do.Injector) (*Database, error) {
    return &Database{URL: "postgres://main.acme.dev:5432/db"}, nil
})
do.ProvideNamed(injector, "backup-db", func(i do.Injector) (*Database, error) {
    return &Database{URL: "postgres://backup.acme.dev:5432/db"}, nil
})
Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

ProvideNamed(injector, "my-service", func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
service, err := InvokeNamed[*exampleService](injector, "my-service")

fmt.Println(err)
fmt.Println(service.Name)
Output:

<nil>
test-service

func ProvideNamedTransient ΒΆ

func ProvideNamedTransient[T any](i Injector, name string, provider Provider[T])

ProvideNamedTransient registers a named factory in the DI container. This allows you to register multiple transient services of the same type with different names for disambiguation.

The service will be recreated each time it is requested, providing a fresh instance.

Example:

// Each invocation creates a new instance
do.ProvideNamedTransient(injector, "request-id", func(i do.Injector) (string, error) {
    return uuid.New().String(), nil
})

// First invocation
id1, _ := do.InvokeNamed[string](injector, "request-id")
// Second invocation - different instance
id2, _ := do.InvokeNamed[string](injector, "request-id")

fmt.Println(id1 != id2) // Output: true
Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

ProvideNamedTransient(injector, "transient-service", func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
service1, _ := InvokeNamed[*exampleService](injector, "transient-service")
service2, _ := InvokeNamed[*exampleService](injector, "transient-service")

fmt.Println(service1 != service2)
Output:

true

func ProvideNamedValue ΒΆ

func ProvideNamedValue[T any](i Injector, name string, value T)

ProvideNamedValue registers a named value in the DI container. This allows you to register multiple values of the same type with different names for disambiguation.

The value is immediately available and will not be recreated on each request.

Example:

do.ProvideNamedValue(injector, "app-config", &Config{Port: 8080})
do.ProvideNamedValue(injector, "db-config", &Config{Port: 5432})
Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

service := &exampleService{Name: "named-eager-service"}
ProvideNamedValue(injector, "my-eager-service", service)
retrieved, err := InvokeNamed[*exampleService](injector, "my-eager-service")

fmt.Println(err)
fmt.Println(retrieved.Name)
Output:

<nil>
named-eager-service

func ProvideTransient ΒΆ

func ProvideTransient[T any](i Injector, provider Provider[T])

ProvideTransient registers a factory in the DI container, using type inference to determine the service name. The service will be recreated each time it is requested, providing a fresh instance.

Play: https://go.dev/play/p/hzOJwtNXwT9

Example:

// Each invocation creates a new instance
do.ProvideTransient(injector, func(i do.Injector) (string, error) {
    return uuid.New().String(), nil
})

// First invocation
id1, _ := do.Invoke[string](injector)
// Second invocation - different instance
id2, _ := do.Invoke[string](injector)

fmt.Println(id1 != id2) // Output: true
Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

ProvideTransient(injector, func(i Injector) (*exampleService, error) {
	return &exampleService{Name: "test-service"}, nil
})
service1, _ := Invoke[*exampleService](injector)
service2, _ := Invoke[*exampleService](injector)

fmt.Println(service1 != service2)
Output:

true

func ProvideValue ΒΆ

func ProvideValue[T any](i Injector, value T)

ProvideValue registers a value in the DI container, using type inference to determine the service name. The value is immediately available and will not be recreated on each request.

Play: https://go.dev/play/p/5TOSiI-c17Y

Example:

ProvideValue(injector, &MyService{})
Example ΒΆ
type exampleService struct {
	Name string
}

injector := New()

service := &exampleService{Name: "eager-service"}
ProvideValue(injector, service)
retrieved, err := Invoke[*exampleService](injector)

fmt.Println(err)
fmt.Println(retrieved.Name)
Output:

<nil>
eager-service

func Shutdown ΒΆ

func Shutdown[T any](i Injector) error

Shutdown stops a service, using type inference to determine the service name. This function performs a graceful shutdown on a service by inferring its name from the type T. The service must implement one of the Shutdowner interfaces.

Parameters:

  • i: The injector containing the service

Returns an error if the shutdown fails, or nil if the shutdown was successful.

Play: https://go.dev/play/p/uOvsiVWa9_R

Example:

err := do.Shutdown[*Database](injector)
if err != nil {
    log.Printf("Database shutdown failed: %v", err)
}
Example ΒΆ
injector := New()

Provide(injector, lifecycleTestServiceProvider)
_, _ = Invoke[*lifecycleTestService](injector)

err := Shutdown[*lifecycleTestService](injector)
fmt.Println(err)
Output:

<nil>

func ShutdownNamed ΒΆ

func ShutdownNamed(i Injector, name string) error

ShutdownNamed stops a named service. This function performs a graceful shutdown on a service with the specified name. The service must implement one of the Shutdowner interfaces.

Parameters:

  • i: The injector containing the service
  • name: The name of the service to shutdown

Returns an error if the shutdown fails, or nil if the shutdown was successful.

Play: https://go.dev/play/p/qAaIo5dWz7J

Example:

err := do.ShutdownNamed(injector, "main-database")
if err != nil {
    log.Printf("Main database shutdown failed: %v", err)
}
Example ΒΆ
injector := New()

ProvideNamed(injector, "main-database", lifecycleTestServiceProvider)
_, _ = InvokeNamed[*lifecycleTestService](injector, "main-database")

err := ShutdownNamed(injector, "main-database")
fmt.Println(err)
Output:

<nil>

func ShutdownNamedWithContext ΒΆ

func ShutdownNamedWithContext(ctx context.Context, i Injector, name string) error

ShutdownNamedWithContext stops a named service with context support. This function performs a graceful shutdown on a service with the specified name and context support for timeout and cancellation. The service must implement one of the Shutdowner interfaces.

Parameters:

  • ctx: Context for cancellation and timeout control
  • i: The injector containing the service
  • name: The name of the service to shutdown

Returns an error if the shutdown fails, or nil if the shutdown was successful.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

err := do.ShutdownNamedWithContext(ctx, injector, "main-database")
if err != nil {
    log.Printf("Main database shutdown failed: %v", err)
}
Example ΒΆ
injector := New()

ProvideNamed(injector, "main-database", lifecycleTestServiceProvider)
_, _ = InvokeNamed[*lifecycleTestService](injector, "main-database")

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

err := ShutdownNamedWithContext(ctx, injector, "main-database")
fmt.Println(err)
Output:

<nil>

func ShutdownWithContext ΒΆ

func ShutdownWithContext[T any](ctx context.Context, i Injector) error

ShutdownWithContext stops a service, using type inference to determine the service name. This function performs a graceful shutdown on a service with context support for timeout and cancellation. The service must implement one of the Shutdowner interfaces.

Parameters:

  • ctx: Context for cancellation and timeout control
  • i: The injector containing the service

Returns an error if the shutdown fails, or nil if the shutdown was successful.

Play: https://go.dev/play/p/qAaIo5dWz7J

Example:

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

err := do.ShutdownWithContext[*Database](ctx, injector)
if err != nil {
    log.Printf("Database shutdown failed: %v", err)
}
Example ΒΆ
injector := New()

Provide(injector, lifecycleTestServiceProvider)
_, _ = Invoke[*lifecycleTestService](injector)

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

err := ShutdownWithContext[*lifecycleTestService](ctx, injector)
fmt.Println(err)
Output:

<nil>

func Transient ΒΆ

func Transient[T any](p Provider[T]) func(Injector)

Transient creates a function that registers a transient service using the default service name. This function is a convenience wrapper for creating transient service registration functions that can be used in packages.

Parameters:

  • p: The provider function that creates the service instance

Returns a function that registers the service as transient when executed.

Play: https://go.dev/play/p/M6-wd1qt-GZ

Example:

// Global to a package
var Package = do.Package(
	do.Transient[*Logger](func(i do.Injector) (*Logger, error) {
    	return &Logger{}, nil
	})
)

func TransientNamed ΒΆ

func TransientNamed[T any](serviceName string, p Provider[T]) func(Injector)

TransientNamed creates a function that registers a transient service with a custom name. This function is a convenience wrapper for creating named transient service registration functions that can be used in packages.

Parameters:

  • serviceName: The custom name for the service
  • p: The provider function that creates the service instance

Returns a function that registers the service as transient with the specified name when executed.

Play: https://go.dev/play/p/d9IJOAbKRUH

Example:

// Global to a package
var Package = do.Package(
	do.TransientNamed[*Logger]("request-logger", func(i do.Injector) (*Logger, error) {
    	return &Logger{}, nil
	})
)

Types ΒΆ

type DAG ΒΆ

type DAG struct {
	// contains filtered or unexported fields
}

DAG represents a Directed Acyclic Graph of services, tracking dependencies and dependents. This type manages the relationships between services to ensure proper initialization order and detect circular dependencies.

The DAG maintains two maps:

  • dependencies: Maps each service to the services it depends on
  • dependents: Maps each service to the services that depend on it

Fields:

  • mu: Read-write mutex for thread-safe access to the graph
  • dependencies: Map of services to their dependencies
  • dependents: Map of services to their dependents

type ExplainInjectorOutput ΒΆ

type ExplainInjectorOutput struct {
	ScopeID   string                       `json:"scope_id"`
	ScopeName string                       `json:"scope_name"`
	DAG       []ExplainInjectorScopeOutput `json:"dag"`
}

ExplainInjectorOutput contains detailed information about an injector and its scope hierarchy. This struct provides a comprehensive view of the injector's scope tree, including all services and their relationships.

func ExplainInjector ΒΆ

func ExplainInjector(scope Injector) ExplainInjectorOutput

ExplainInjector returns a human readable description of the injector, with services and scope tree. This function provides a comprehensive view of the injector's structure, including all scopes, services, and their relationships in a hierarchical format.

Parameters:

  • scope: The injector to explain

Returns a detailed explanation of the injector's structure and contents.

Example:

explanation := do.ExplainInjector(injector)
fmt.Println(explanation.String())

Play: https://go.dev/play/p/mRs4Q7TJ5jj

Output example:

Scope ID: root
Scope name: Root Scope

DAG:
 |\_ Root Scope (ID: root)
 |   * 😴 Database
 |   * πŸ” Config
 |   |\_ API Scope (ID: api)
 |   |   * 🏭 Logger
 |   |   * πŸ”— DatabaseInterface
Example ΒΆ
injector := New()

ProvideNamedValue(injector, "value", 42)
ProvideNamed(injector, "service1", newExplainTestService)
ProvideNamedValue(injector, "service2", "value")

explanation := ExplainInjector(injector)
fmt.Println(explanation.ScopeName)
fmt.Println(len(explanation.DAG))
Output:

[root]
1

func (*ExplainInjectorOutput) String ΒΆ

func (id *ExplainInjectorOutput) String() string

String returns a formatted string representation of the injector explanation. This method provides a human-readable description of the injector including its scope hierarchy and all services in a tree-like format.

Returns a formatted string describing the injector and its scope hierarchy.

type ExplainInjectorScopeOutput ΒΆ

type ExplainInjectorScopeOutput struct {
	ScopeID   string                         `json:"scope_id"`
	ScopeName string                         `json:"scope_name"`
	Scope     Injector                       `json:"scope"`
	Services  []ExplainInjectorServiceOutput `json:"services"`
	Children  []ExplainInjectorScopeOutput   `json:"children"`

	IsAncestor bool `json:"is_ancestor"`
	IsChildren bool `json:"is_children"`
}

ExplainInjectorScopeOutput contains information about a single scope in the injector hierarchy. This struct represents a scope and its services, along with its position in the scope tree.

func (*ExplainInjectorScopeOutput) String ΒΆ

func (ids *ExplainInjectorScopeOutput) String() string

String returns a formatted string representation of the scope. This method provides a human-readable description of the scope including its services and child scopes.

Returns a formatted string describing the scope.

type ExplainInjectorServiceOutput ΒΆ

type ExplainInjectorServiceOutput struct {
	ServiceName      string        `json:"service_name"`
	ServiceType      ServiceType   `json:"service_type"`
	ServiceTypeIcon  string        `json:"service_type_icon"`
	ServiceBuildTime time.Duration `json:"service_build_time,omitempty"`
	IsHealthchecker  bool          `json:"is_healthchecker"`
	IsShutdowner     bool          `json:"is_shutdowner"`
}

ExplainInjectorServiceOutput contains information about a service in the scope explanation. This struct provides details about a service's type, capabilities, and lifecycle state.

func (*ExplainInjectorServiceOutput) String ΒΆ

func (idss *ExplainInjectorServiceOutput) String() string

String returns a formatted string representation of the service. This method provides a human-readable description of the service including its type icon and capabilities indicators.

Returns a formatted string describing the service.

type ExplainServiceDependencyOutput ΒΆ

type ExplainServiceDependencyOutput struct {
	ScopeID   string                           `json:"scope_id"`
	ScopeName string                           `json:"scope_name"`
	Service   string                           `json:"service"`
	Recursive []ExplainServiceDependencyOutput `json:"recursive"`
}

ExplainServiceDependencyOutput contains information about a service dependency relationship. This struct represents either a dependency (service this depends on) or a dependent (service that depends on this) in the dependency graph.

Fields:

  • ScopeID: The unique identifier of the scope containing the related service
  • ScopeName: The human-readable name of the scope containing the related service
  • Service: The name of the related service
  • Recursive: Nested dependency relationships (for transitive dependencies)

func (*ExplainServiceDependencyOutput) String ΒΆ

func (sdd *ExplainServiceDependencyOutput) String() string

String returns a formatted string representation of the dependency relationship. This method provides a human-readable description of the dependency, including nested recursive dependencies with proper indentation.

Returns a formatted string describing the dependency relationship.

type ExplainServiceOutput ΒΆ

type ExplainServiceOutput struct {
	ScopeID          string                           `json:"scope_id"`
	ScopeName        string                           `json:"scope_name"`
	ServiceName      string                           `json:"service_name"`
	ServiceType      ServiceType                      `json:"service_type"`
	ServiceBuildTime time.Duration                    `json:"service_build_time,omitempty"`
	Invoked          *stacktrace.Frame                `json:"invoked"`
	Dependencies     []ExplainServiceDependencyOutput `json:"dependencies"`
	Dependents       []ExplainServiceDependencyOutput `json:"dependents"`
}

ExplainServiceOutput contains detailed information about a service for debugging and analysis. This struct provides comprehensive information about a service's location, type, dependencies, and lifecycle state.

func ExplainNamedService ΒΆ

func ExplainNamedService(scope Injector, name string) (description ExplainServiceOutput, ok bool)

ExplainNamedService returns a human readable description of the service by name. This function provides detailed information about a service including its scope, type, dependencies, and lifecycle state. The service must be registered before calling this function.

Parameters:

  • scope: The injector to search for the service
  • name: The name of the service to explain

Returns a service explanation and a boolean indicating if the service was found. The boolean is false if the service is not found.

Note: Please call Invoke[T] before ExplainNamedService[T] to ensure that the service is registered.

Play: https://go.dev/play/p/GTcGyPFC8IB

Example:

// First invoke the service to ensure it's registered
	db := do.MustInvokeNamed[*Database](injector, "main-db")

// Then explain it
	explanation, found := do.ExplainNamedService(injector, "main-db")
	if found {
	    fmt.Println(explanation.String())
	}
Example ΒΆ
injector := New()

ProvideNamedValue(injector, "value", 42)
ProvideNamed(injector, "my-service", newExplainTestService)
_, _ = InvokeNamed[*explainTestService](injector, "my-service")

explanation, found := ExplainNamedService(injector, "my-service")

// to prevent flakiness
explanation.ScopeID = "980e2f60-d340-4776-86dd-6aa1d3c27860"
explanation.ServiceBuildTime = 10 * time.Millisecond
explanation.Invoked = &stacktrace.Frame{
	Function: "newExplainTestService",
	File:     "di_explain_example_test.go", // remove absolute path
	Line:     42,
}

fmt.Println(found)
fmt.Println(explanation.ServiceName)
fmt.Println(explanation.ServiceType)
fmt.Println(explanation.String())
Output:

true
my-service
lazy

Scope ID: 980e2f60-d340-4776-86dd-6aa1d3c27860
Scope name: [root]

Service name: my-service
Service type: lazy
Service build time: 10ms
Invoked: di_explain_example_test.go:newExplainTestService:42

Dependencies:
* value from scope [root]

Dependents:

func ExplainService ΒΆ

func ExplainService[T any](i Injector) (description ExplainServiceOutput, ok bool)

ExplainService returns a human readable description of the service. This function provides detailed information about a service including its scope, type, dependencies, and lifecycle state. The service must be registered before calling this function.

Parameters:

  • i: The injector to search for the service

Returns a service explanation and a boolean indicating if the service was found. The boolean is false if the service is not found.

Note: Please call Invoke[T] before ExplainService[T] to ensure that the service is registered.

Play: https://go.dev/play/p/Eii-vX9Rc-a

Example:

// First invoke the service to ensure it's registered
	db := do.MustInvoke[*Database](injector)

// Then explain it
	explanation, found := do.ExplainService[*Database](injector)
	if found {
		fmt.Println(explanation.String())
	}
Example ΒΆ
injector := New()

ProvideNamedValue(injector, "value", 42)
Provide(injector, newExplainTestService)
_, _ = Invoke[*explainTestService](injector)

explanation, found := ExplainService[*explainTestService](injector)

// to prevent flakiness
explanation.ScopeID = "980e2f60-d340-4776-86dd-6aa1d3c27860"
explanation.ServiceBuildTime = 10 * time.Millisecond
explanation.Invoked = &stacktrace.Frame{
	Function: "newExplainTestService",
	File:     "di_explain_example_test.go", // remove absolute path
	Line:     42,
}

fmt.Println(found)
fmt.Println(explanation.ServiceName)
fmt.Println(explanation.ServiceType)
fmt.Println(explanation.String())
Output:

true
*gitee.com/supos-community-edition/di/v2.explainTestService
lazy

Scope ID: 980e2f60-d340-4776-86dd-6aa1d3c27860
Scope name: [root]

Service name: *gitee.com/supos-community-edition/di/v2.explainTestService
Service type: lazy
Service build time: 10ms
Invoked: di_explain_example_test.go:newExplainTestService:42

Dependencies:
* value from scope [root]

Dependents:

func (*ExplainServiceOutput) String ΒΆ

func (sd *ExplainServiceOutput) String() string

String returns a formatted string representation of the service explanation. This method provides a human-readable description of the service including its scope, type, build time, and dependency relationships.

Returns a formatted string describing the service.

type Healthchecker ΒΆ

type Healthchecker interface {
	HealthCheck() error
}

Healthchecker is an interface that services can implement to provide health checking capabilities. Services implementing this interface can be health-checked by the DI container to ensure they are functioning correctly.

The HealthCheck method should perform a quick check to verify the service is healthy. It should return nil if the service is healthy, or an error describing the health issue.

Example:

type Database struct {
    conn *sql.DB
}

func (db *Database) HealthCheck() error {
    return db.conn.Ping()
}

type HealthcheckerWithContext ΒΆ

type HealthcheckerWithContext interface {
	HealthCheck(context.Context) error
}

HealthcheckerWithContext is an interface that services can implement to provide health checking capabilities with context support. This allows for timeout and cancellation control during health checks.

The HealthCheck method should perform a quick check to verify the service is healthy. It should respect the provided context for cancellation and timeout. It should return nil if the service is healthy, or an error describing the health issue.

Example:

type Database struct {
    conn *sql.DB
}

func (db *Database) HealthCheck(ctx context.Context) error {
    return db.conn.PingContext(ctx)
}

type Injector ΒΆ

type Injector interface {

	// ID returns the unique identifier of the injector.
	ID() string

	// Name returns the human-readable name of the injector.
	Name() string

	// Scope creates a new child scope with the given name.
	// Optional package functions can be provided to execute during scope creation.
	Scope(string, ...func(Injector)) *Scope

	// RootScope returns the root scope of the injector hierarchy.
	RootScope() *RootScope

	// Ancestors returns the list of all parent scopes in order from immediate parent to root.
	Ancestors() []*Scope

	// Children returns the list of immediate child scopes.
	Children() []*Scope

	// ChildByID searches for a child scope by its unique ID across the entire scope hierarchy.
	ChildByID(string) (*Scope, bool)

	// ChildByName searches for a child scope by its name across the entire scope hierarchy.
	ChildByName(string) (*Scope, bool)

	// ListProvidedServices returns all services available in the current scope and all its ancestor scopes.
	ListProvidedServices() []ServiceDescription

	// ListInvokedServices returns only the services that have been actually invoked in the current scope and its ancestors.
	ListInvokedServices() []ServiceDescription

	// HealthCheck performs health checks on all services in the current scope and its ancestors.
	HealthCheck() map[string]error

	// HealthCheckWithContext performs health checks with context support for cancellation and timeouts.
	HealthCheckWithContext(context.Context) map[string]error

	// Shutdown gracefully shuts down the injector and all its descendant scopes.
	Shutdown() *ShutdownReport

	// ShutdownWithContext gracefully shuts down the injector and all its descendant scopes with context support.
	ShutdownWithContext(context.Context) *ShutdownReport
	// contains filtered or unexported methods
}

Injector is the main interface for dependency injection containers. It provides methods for service registration, resolution, lifecycle management, and scope hierarchy management.

The Injector interface is implemented by both RootScope and Scope types, allowing for a consistent API across different levels of the scope hierarchy.

type InjectorOpts ΒΆ

type InjectorOpts struct {
	// HookBeforeRegistration is called before a service is registered in a scope.
	// This hook can be used for validation, logging, or other pre-registration tasks.
	HookBeforeRegistration []func(scope *Scope, serviceName string)

	// HookAfterRegistration is called after a service is successfully registered in a scope.
	// This hook can be used for logging, metrics collection, or other post-registration tasks.
	HookAfterRegistration []func(scope *Scope, serviceName string)

	// HookBeforeInvocation is called before a service is invoked (instantiated).
	// This hook can be used for logging, metrics, or other pre-invocation tasks.
	HookBeforeInvocation []func(scope *Scope, serviceName string)

	// HookAfterInvocation is called after a service is invoked, with the result error.
	// This hook can be used for logging, metrics collection, or error handling.
	HookAfterInvocation []func(scope *Scope, serviceName string, err error)

	// HookBeforeShutdown is called before a service is shut down.
	// This hook can be used for cleanup preparation or logging.
	HookBeforeShutdown []func(scope *Scope, serviceName string)

	// HookAfterShutdown is called after a service is shut down, with the result error.
	// This hook can be used for logging, metrics collection, or error handling.
	HookAfterShutdown []func(scope *Scope, serviceName string, err error)

	// Logf is the logging function used by the DI container for internal logging.
	// If not provided, no logging will occur. This function should handle the format
	// string and arguments similar to fmt.Printf.
	Logf func(format string, args ...any)

	// HealthCheckParallelism controls the number of concurrent health checks that can run simultaneously.
	// Default: all health checks run in parallel (unlimited).
	// Setting this to a positive number limits the concurrency for better resource management.
	HealthCheckParallelism uint

	// HealthCheckGlobalTimeout sets a global timeout for all health check operations.
	// This timeout applies to the entire health check process across all services.
	// Default: no timeout (health checks can run indefinitely).
	HealthCheckGlobalTimeout time.Duration

	// HealthCheckTimeout sets a timeout for individual service health checks.
	// This timeout applies to each service's health check method.
	// Default: no timeout (individual health checks can run indefinitely).
	HealthCheckTimeout time.Duration

	// StructTagKey specifies the tag key used for struct field injection.
	// Default: "do" (see DefaultStructTagKey constant).
	// This allows customization of the struct tag format for injection.
	StructTagKey string
}

InjectorOpts contains all configuration options for the dependency injection container. These options control logging, hooks, health checks, and other behavioral aspects of the DI container.

type Provider ΒΆ

type Provider[T any] func(Injector) (T, error)

Provider is a function type that creates and returns a service instance of type T. This is the core abstraction for service creation in the dependency injection container.

The provider function receives an Injector instance that can be used to resolve dependencies for the service being created.

Example:

func NewMyService(i do.Injector) (*MyService, error) {
    db := do.MustInvoke[*Database](i)
    config := do.MustInvoke[*Config](i)
    return &MyService{DB: db, Config: config}, nil
}

// Register the provider
do.Provide(injector, NewMyService)

type RootScope ΒΆ

type RootScope struct {
	// contains filtered or unexported fields
}

RootScope is the top-level scope in the dependency injection container hierarchy. It serves as the entry point for all DI operations and manages the overall container lifecycle.

Key responsibilities:

  • Service registration and resolution
  • Child scope management
  • Health check coordination
  • Shutdown orchestration
  • Dependency graph management

func New ΒΆ

func New(packages ...func(Injector)) *RootScope

New creates a new dependency injection container with default options. This is the primary entry point for creating a new DI container.

Parameters:

  • packages: Optional package functions to execute during initialization

Returns a new RootScope instance ready for service registration.

Play: https://go.dev/play/p/-Fvet5zLoVY

Example:

injector := do.New()
do.Provide(injector, func(i do.Injector) (*MyService, error) {
    return &MyService{}, nil
})
Example ΒΆ
injector := New()

ProvideNamedValue(injector, "PG_URI", "postgres://user:pass@host:5432/db")
uri, err := InvokeNamed[string](injector, "PG_URI")

fmt.Println(uri)
fmt.Println(err)
Output:

postgres://user:pass@host:5432/db
<nil>

func NewWithOpts ΒΆ

func NewWithOpts(opts *InjectorOpts, packages ...func(Injector)) *RootScope

NewWithOpts creates a new dependency injection container with custom options. This allows you to configure logging, hooks, health check settings, and other options.

Parameters:

  • opts: Configuration options for the injector
  • packages: Optional package functions to execute during initialization

Returns a new RootScope instance with the specified configuration.

Play: https://go.dev/play/p/SmhFpWZGKUw

Example:

opts := &do.InjectorOpts{
    Logf: func(format string, args ...any) {
        log.Printf(format, args...)
    },
    HealthCheckParallelism: 10,
}
injector := do.NewWithOpts(opts)
Example ΒΆ
injector := NewWithOpts(&InjectorOpts{
	HookAfterShutdown: []func(scope *Scope, serviceName string, err error){
		func(scope *Scope, serviceName string, err error) {
			fmt.Printf("service shutdown: %s\n", serviceName)
		},
	},
})

ProvideNamed(injector, "PG_URI", func(i Injector) (string, error) {
	return "postgres://user:pass@host:5432/db", nil
})
MustInvokeNamed[string](injector, "PG_URI")
report := injector.Shutdown()
fmt.Println(report.Succeed)
fmt.Println(len(report.Errors))
Output:

service shutdown: PG_URI
true
0

func (*RootScope) AddAfterInvocationHook ΒΆ

func (s *RootScope) AddAfterInvocationHook(hook func(*Scope, string, error))

AddAfterInvocationHook adds a hook that will be called after a service is invoked.

Play: https://go.dev/play/p/IstT_4oovQD

Example ΒΆ
injector := New()

injector.AddAfterInvocationHook(func(scope *Scope, serviceName string, err error) {
	fmt.Printf("invoked service: %s, error: %v\n", serviceName, err)
})

ProvideNamedValue(injector, "test", "value")
_, _ = InvokeNamed[string](injector, "test")
Output:

invoked service: test, error: <nil>

func (*RootScope) AddAfterRegistrationHook ΒΆ

func (s *RootScope) AddAfterRegistrationHook(hook func(*Scope, string))

AddAfterRegistrationHook adds a hook that will be called after a service is registered.

Play: https://go.dev/play/p/IstT_4oovQD

Example ΒΆ
injector := New()

injector.AddAfterRegistrationHook(func(scope *Scope, serviceName string) {
	fmt.Printf("registered service: %s\n", serviceName)
})

ProvideNamedValue(injector, "test", "value")
Output:

registered service: test

func (*RootScope) AddAfterShutdownHook ΒΆ

func (s *RootScope) AddAfterShutdownHook(hook func(*Scope, string, error))

AddAfterShutdownHook adds a hook that will be called after a service is shutdown.

Play: https://go.dev/play/p/FFKDcV0hMJx

Example ΒΆ
injector := New()

injector.AddAfterShutdownHook(func(scope *Scope, serviceName string, err error) {
	fmt.Printf("shut down service: %s, error: %v\n", serviceName, err)
})

ProvideNamedValue(injector, "test", "value")
_ = injector.Shutdown()
Output:

shut down service: test, error: <nil>

func (*RootScope) AddBeforeInvocationHook ΒΆ

func (s *RootScope) AddBeforeInvocationHook(hook func(*Scope, string))

AddBeforeInvocationHook adds a hook that will be called before a service is invoked.

Play: https://go.dev/play/p/IstT_4oovQD

Example ΒΆ
injector := New()

injector.AddBeforeInvocationHook(func(scope *Scope, serviceName string) {
	fmt.Printf("invoking service: %s\n", serviceName)
})

ProvideNamedValue(injector, "test", "value")
_, _ = InvokeNamed[string](injector, "test")
Output:

invoking service: test

func (*RootScope) AddBeforeRegistrationHook ΒΆ

func (s *RootScope) AddBeforeRegistrationHook(hook func(*Scope, string))

AddBeforeRegistrationHook adds a hook that will be called before a service is registered.

Play: https://go.dev/play/p/IstT_4oovQD

Example ΒΆ
injector := New()

injector.AddBeforeRegistrationHook(func(scope *Scope, serviceName string) {
	fmt.Printf("registering service: %s\n", serviceName)
})

ProvideNamedValue(injector, "test", "value")
Output:

registering service: test

func (*RootScope) AddBeforeShutdownHook ΒΆ

func (s *RootScope) AddBeforeShutdownHook(hook func(*Scope, string))

AddBeforeShutdownHook adds a hook that will be called before a service is shutdown.

Play: https://go.dev/play/p/FFKDcV0hMJx

Example ΒΆ
injector := New()

injector.AddBeforeShutdownHook(func(scope *Scope, serviceName string) {
	fmt.Printf("shutting down service: %s\n", serviceName)
})

ProvideNamedValue(injector, "test", "value")
_ = injector.Shutdown()
Output:

shutting down service: test

func (*RootScope) Ancestors ΒΆ

func (s *RootScope) Ancestors() []*Scope

Ancestors returns an empty slice since the root scope has no ancestors.

func (*RootScope) ChildByID ΒΆ

func (s *RootScope) ChildByID(id string) (*Scope, bool)

ChildByID searches for a child scope by its unique ID across the entire scope hierarchy.

func (*RootScope) ChildByName ΒΆ

func (s *RootScope) ChildByName(name string) (*Scope, bool)

ChildByName searches for a child scope by its name across the entire scope hierarchy.

func (*RootScope) Children ΒΆ

func (s *RootScope) Children() []*Scope

Children returns the list of immediate child scopes.

func (*RootScope) Clone ΒΆ

func (s *RootScope) Clone() *RootScope

Clone clones injector with provided services but not with invoked instances.

Play: https://go.dev/play/p/DqIlXhZ8c4t

Example ΒΆ
injector := New()
ProvideNamedValue(injector, "test", "value")

clone := injector.Clone()
services := clone.ListProvidedServices()

fmt.Println(len(services))
fmt.Println(services[0].Service)
Output:

1
test

func (*RootScope) CloneWithOpts ΒΆ

func (s *RootScope) CloneWithOpts(opts *InjectorOpts) *RootScope

CloneWithOpts clones injector with provided services but not with invoked instances, with options.

Play: https://go.dev/play/p/fT-v63fbFk5

Example ΒΆ
injector := New()
ProvideNamedValue(injector, "test", "value")

clone := injector.CloneWithOpts(&InjectorOpts{
	HookAfterShutdown: []func(scope *Scope, serviceName string, err error){
		func(scope *Scope, serviceName string, err error) {
			fmt.Printf("shutdown: %s\n", serviceName)
		},
	},
})

_ = clone.Shutdown()
Output:

shutdown: test

func (*RootScope) HealthCheck ΒΆ

func (s *RootScope) HealthCheck() map[string]error

HealthCheck performs health checks on all services in the root scope and all its descendant scopes.

func (*RootScope) HealthCheckWithContext ΒΆ

func (s *RootScope) HealthCheckWithContext(ctx context.Context) map[string]error

HealthCheckWithContext performs health checks with context support for cancellation and timeouts.

func (*RootScope) ID ΒΆ

func (s *RootScope) ID() string

ID returns the unique identifier of the root scope.

func (*RootScope) InstanceForEach ΒΆ

func (s *RootScope) InstanceForEach(cb func(string, *Scope, any) bool)

func (*RootScope) ListInvokedServices ΒΆ

func (s *RootScope) ListInvokedServices() []ServiceDescription

ListInvokedServices returns all services that have been invoked in the root scope and all its descendant scopes.

func (*RootScope) ListProvidedServices ΒΆ

func (s *RootScope) ListProvidedServices() []ServiceDescription

ListProvidedServices returns all services available in the root scope and all its descendant scopes.

func (*RootScope) Name ΒΆ

func (s *RootScope) Name() string

Name returns the name of the root scope.

func (*RootScope) RootScope ΒΆ

func (s *RootScope) RootScope() *RootScope

RootScope returns the root scope itself (this instance).

func (*RootScope) Scope ΒΆ

func (s *RootScope) Scope(name string, p ...func(Injector)) *Scope

Scope creates a new child scope under the root scope.

func (*RootScope) ServiceExists ΒΆ

func (s *RootScope) ServiceExists(name string) bool

func (*RootScope) ServiceGet ΒΆ

func (s *RootScope) ServiceGet(name string) (any, bool)

func (*RootScope) Shutdown ΒΆ

func (s *RootScope) Shutdown() *ShutdownReport

Shutdown gracefully shuts down the root scope and all its descendant scopes.

func (*RootScope) ShutdownOnSignals ΒΆ

func (s *RootScope) ShutdownOnSignals(signals ...os.Signal) (os.Signal, *ShutdownReport)

ShutdownOnSignals listens for the provided signals in order to gracefully stop services. It will block until receiving any of these signals. If no signal is provided, syscall.SIGTERM and os.Interrupt will be handled by default.

Example ΒΆ
// This example is commented out because it would block waiting for signals
// injector := New()
// signal, errors := injector.ShutdownOnSignals(syscall.SIGINT, syscall.SIGTERM)
// fmt.Println(signal)
// fmt.Println(errors.Len())

func (*RootScope) ShutdownOnSignalsWithContext ΒΆ

func (s *RootScope) ShutdownOnSignalsWithContext(ctx context.Context, signals ...os.Signal) (os.Signal, *ShutdownReport)

ShutdownOnSignalsWithContext listens for the provided signals in order to gracefully stop services. It will block until receiving any of these signals. If no signal is provided, syscall.SIGTERM and os.Interrupt will be handled by default.

Example ΒΆ
// This example is commented out because it would block waiting for signals
// injector := New()
// ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
// defer cancel()
// signal, errors := injector.ShutdownOnSignalsWithContext(ctx, syscall.SIGINT, syscall.SIGTERM)
// fmt.Println(signal)
// fmt.Println(errors.Len())

func (*RootScope) ShutdownWithContext ΒΆ

func (s *RootScope) ShutdownWithContext(ctx context.Context) *ShutdownReport

ShutdownWithContext gracefully shuts down the root scope and all its descendant scopes with context support. This method ensures proper cleanup of the health check pool and all registered services.

type Scope ΒΆ

type Scope struct {
	// contains filtered or unexported fields
}

Scope represents a dependency injection container that can contain services and child scopes. Scopes form a hierarchical tree structure where child scopes can access services from their parent scopes, but not vice versa.

Key features:

  • Hierarchical service resolution (child scopes can access parent services)
  • Isolated service registration (services in child scopes don't affect parents)
  • Thread-safe operations
  • Service lifecycle management (health checks, shutdown)
  • Observability and debugging support

func (*Scope) Ancestors ΒΆ

func (s *Scope) Ancestors() []*Scope

Ancestors returns the list of all parent scopes in order from immediate parent to root. This is useful for understanding the scope hierarchy and for operations that need to traverse up the scope tree.

Returns an empty slice for the root scope, and a slice of parent scopes for child scopes, ordered from immediate parent to root.

Play: https://go.dev/play/p/e_oxd7b-q9h

Example ΒΆ
injector := New()
apiScope := injector.Scope("api")
userScope := apiScope.Scope("user")
ancestors := userScope.Ancestors()

fmt.Println(len(ancestors))
fmt.Println(ancestors[0].Name())
Output:

2
api

func (*Scope) ChildByID ΒΆ

func (s *Scope) ChildByID(id string) (*Scope, bool)

ChildByID searches for a child scope by its unique ID across the entire scope hierarchy. This method performs a recursive search through all descendant scopes.

Parameters:

  • id: The unique ID of the scope to find

Returns the found scope and true if found, or nil and false if not found.

Play: https://go.dev/play/p/pao_03UdGE2

Example ΒΆ
injector := New()
apiScope := injector.Scope("api")
userScope := apiScope.Scope("user")

child, found := apiScope.ChildByID(userScope.ID())
fmt.Println(found)
fmt.Println(child.Name())
Output:

true
user

func (*Scope) ChildByName ΒΆ

func (s *Scope) ChildByName(name string) (*Scope, bool)

ChildByName searches for a child scope by its name across the entire scope hierarchy. This method performs a recursive search through all descendant scopes.

Parameters:

  • name: The name of the scope to find

Returns the found scope and true if found, or nil and false if not found.

Play: https://go.dev/play/p/pao_03UdGE2

Example ΒΆ
injector := New()
apiScope := injector.Scope("api")
_ = apiScope.Scope("user")

child, found := apiScope.ChildByName("user")
fmt.Println(found)
fmt.Println(child.Name())
Output:

true
user

func (*Scope) Children ΒΆ

func (s *Scope) Children() []*Scope

Children returns the list of immediate child scopes. This method only returns direct children, not grandchildren or deeper descendants.

Returns a slice of child scopes. The order is not guaranteed to be stable.

Play: https://go.dev/play/p/pao_03UdGE2

Example ΒΆ
injector := New()
apiScope := injector.Scope("api")
_ = apiScope.Scope("user")
_ = apiScope.Scope("admin")
children := apiScope.Children()

fmt.Println(len(children))
Output:

2

func (*Scope) HealthCheck ΒΆ

func (s *Scope) HealthCheck() map[string]error

HealthCheck performs health checks on all services in the current scope and its ancestors that implement the Healthchecker interface.

Returns a map of service names to error values. A nil error indicates a successful health check.

Play: https://go.dev/play/p/pJcJGOF5zeK

Example ΒΆ
injector := New()
scope := injector.Scope("api")

ProvideNamed(scope, "db", scopeDbServiceProvider)
_, _ = InvokeNamed[*scopeDbService](scope, "db")
health := scope.HealthCheck()

fmt.Println(len(health))
Output:

1

func (*Scope) HealthCheckWithContext ΒΆ

func (s *Scope) HealthCheckWithContext(ctx context.Context) map[string]error

HealthCheckWithContext performs health checks on all services in the current scope and its ancestors that implement the Healthchecker interface, with context support for cancellation and timeouts.

Parameters:

  • ctx: Context for cancellation and timeout control

Returns a map of service names to error values. A nil error indicates a successful health check.

Play: https://go.dev/play/p/pJcJGOF5zeK

Example ΒΆ
injector := New()
scope := injector.Scope("api")

ProvideNamed(scope, "db", scopeDbServiceProvider)
_, _ = InvokeNamed[*scopeDbService](scope, "db")

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

health := scope.HealthCheckWithContext(ctx)
fmt.Println(len(health))
Output:

1

func (*Scope) ID ΒΆ

func (s *Scope) ID() string

ID returns the unique identifier of the scope. This ID is generated using UUID and is immutable throughout the scope's lifetime.

Play: https://go.dev/play/p/pao_03UdGE2

Example ΒΆ
injector := New()
scope := injector.Scope("api")

fmt.Println(scope.ID() != "")
Output:

true

func (*Scope) InstanceForEach ΒΆ

func (s *Scope) InstanceForEach(cb func(name string, scope *Scope, service any) bool)

func (*Scope) ListInvokedServices ΒΆ

func (s *Scope) ListInvokedServices() []ServiceDescription

ListInvokedServices returns only the services that have been actually invoked (instantiated) in the current scope and its ancestors. This is useful for understanding which services are actually being used and for debugging dependency issues.

Returns a slice of ServiceDescription objects representing only the invoked services.

Play: https://go.dev/play/p/pJcJGOF5zeK

Example ΒΆ
type Configuration struct {
	Port int
}

injector := New()
scope := injector.Scope("api")

ProvideNamedValue(scope, "config", Configuration{Port: 8080})
_, _ = InvokeNamed[Configuration](scope, "config")
services := scope.ListInvokedServices()

fmt.Println(len(services))
fmt.Println(services[0].Service)
Output:

1
config

func (*Scope) ListProvidedServices ΒΆ

func (s *Scope) ListProvidedServices() []ServiceDescription

ListProvidedServices returns all services available in the current scope and all its ancestor scopes. This provides a complete view of the service hierarchy, showing all services that can be accessed from the current scope.

Returns a slice of ServiceDescription objects representing all available services, including those inherited from parent scopes.

Play: https://go.dev/play/p/e_oxd7b-q9h

Example ΒΆ
type Configuration struct {
	Port int
}

injector := New()
scope := injector.Scope("api")

ProvideNamedValue(scope, "config", Configuration{Port: 8080})
services := scope.ListProvidedServices()

fmt.Println(len(services))
fmt.Println(services[0].Service)
Output:

1
config

func (*Scope) Name ΒΆ

func (s *Scope) Name() string

Name returns the human-readable name of the scope. This name is provided when creating the scope and is immutable.

Play: https://go.dev/play/p/pao_03UdGE2

Example ΒΆ
injector := New()
scope := injector.Scope("api")

fmt.Println(scope.Name())
Output:

api

func (*Scope) RootScope ΒΆ

func (s *Scope) RootScope() *RootScope

RootScope returns the root scope of the scope hierarchy. All scopes in a hierarchy share the same root scope, regardless of their depth.

Play: https://go.dev/play/p/pao_03UdGE2

Example ΒΆ
injector := New()
apiScope := injector.Scope("api")
userScope := apiScope.Scope("user")
root := userScope.RootScope()

fmt.Println(root.Name())
Output:

[root]

func (*Scope) Scope ΒΆ

func (s *Scope) Scope(name string, packages ...func(Injector)) *Scope

Scope creates a new child scope with the given name. Child scopes inherit access to services from their parent scopes, but services registered in child scopes are not accessible to parents.

Parameters:

  • name: The name for the new child scope (must be unique within the parent)
  • packages: Optional package functions to execute in the new scope

Returns the newly created child scope.

Play: https://go.dev/play/p/pao_03UdGE2

Panics if a scope with the same name already exists in the parent.

Example ΒΆ
injector := New()
apiScope := injector.Scope("api")
userScope := apiScope.Scope("user")

fmt.Println(userScope.Name())
Output:

user

func (*Scope) Shutdown ΒΆ

func (s *Scope) Shutdown() *ShutdownReport

Shutdown gracefully shuts down the scope and all its children. This method calls ShutdownWithContext with a background context.

Returns a ShutdownReport containing any errors and timings that occurred during shutdown.

Play: https://go.dev/play/p/nkiBBYow2d5

Example ΒΆ
injector := New()
scope := injector.Scope("api")

ProvideNamed(scope, "db", scopeDbServiceProvider)
_, _ = InvokeNamed[*scopeDbService](scope, "db")

report := scope.Shutdown()
fmt.Println(report.Succeed)
fmt.Println(len(report.Services))
fmt.Println(report.Error())
Output:

false
1
DI: shutdown errors:
  - api > db: shutdown error

func (*Scope) ShutdownWithContext ΒΆ

func (s *Scope) ShutdownWithContext(ctx context.Context) *ShutdownReport

ShutdownWithContext gracefully shuts down the scope and all its children with context support. This method performs shutdown operations in parallel for better performance.

Parameters:

  • ctx: Context for cancellation and timeout control

Returns a ShutdownReport containing any errors and timings that occurred during shutdown.

Play: https://go.dev/play/p/nkiBBYow2d5

Example ΒΆ
injector := New()

// Register a simple service without shutdown capability
ProvideNamedValue(injector, "config", "value")
_, _ = InvokeNamed[string](injector, "config")

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()

report := injector.ShutdownWithContext(ctx)
fmt.Println(report.Succeed)
fmt.Println(len(report.Services))
fmt.Println(report.Error())
Output:

true
1
Example (Timeout) ΒΆ
injector := New()
scope := injector.Scope("api")

ProvideNamed(scope, "db", scopeDbServiceProvider)
_, _ = InvokeNamed[*scopeDbService](scope, "db")

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()

time.Sleep(100 * time.Millisecond) // will trigger timeout

report := injector.ShutdownWithContext(ctx)
fmt.Println(report.Error())
Output:

DI: shutdown errors:
  - api > db: context deadline exceeded

type ServiceDescription ΒΆ

type ServiceDescription struct {
	ScopeID   string
	ScopeName string
	Service   string
}

ServiceDescription represents a service in the dependency graph (DAG), identified by scope ID, scope name, and service name. This type is used to uniquely identify services across the entire scope hierarchy for dependency tracking.

Fields:

  • ScopeID: The unique identifier of the scope containing the service
  • ScopeName: The human-readable name of the scope containing the service
  • Service: The name of the service within the scope

type ServiceType ΒΆ

type ServiceType string

ServiceType represents the different types of services that can be registered in the dependency injection container. Each type has different lifecycle and instantiation behavior.

const (
	// ServiceTypeLazy represents a service that is instantiated only when first requested.
	// The service instance is cached and reused for subsequent requests.
	ServiceTypeLazy ServiceType = "lazy"

	// ServiceTypeEager represents a service that is instantiated immediately when registered.
	// The service is always available and ready to use.
	ServiceTypeEager ServiceType = "eager"

	// ServiceTypeTransient represents a service that is recreated each time it is requested.
	// No singleton caching is performed, ensuring a fresh instance every time. It is basically a factory.
	ServiceTypeTransient ServiceType = "transient"

	// ServiceTypeAlias represents a service that is an alias to another service.
	// It provides a different interface or name for accessing an existing service.
	ServiceTypeAlias ServiceType = "alias"
)

type ShutdownReport ΒΆ

type ShutdownReport struct {
	Succeed             bool
	Services            []ServiceDescription
	Errors              map[ServiceDescription]error
	ShutdownTime        time.Duration
	ServiceShutdownTime map[ServiceDescription]time.Duration
}

ShutdownReport represents the result of a shutdown operation. It includes overall success, the list of services that were shut down, any errors encountered, total shutdown time, and per-service shutdown durations.

It implements the error interface, returning a formatted description of errors when any occurred, or a "no shutdown errors" message otherwise.

func (ShutdownReport) Error ΒΆ

func (r ShutdownReport) Error() string

Error implements the error interface for ShutdownReport. If there are errors, it returns a multiline description. Otherwise a friendly message.

type Shutdowner ΒΆ

type Shutdowner interface {
	Shutdown()
}

Shutdowner is an interface that services can implement to provide graceful shutdown capabilities. Services implementing this interface will be called during container shutdown to perform cleanup operations.

The Shutdown method should perform any necessary cleanup, such as closing connections, flushing buffers, or stopping background processes.

Example:

type Logger struct {
    file *os.File
}

func (l *Logger) Shutdown() {
    l.file.Close()
}

type ShutdownerWithContext ΒΆ

type ShutdownerWithContext interface {
	Shutdown(context.Context)
}

ShutdownerWithContext is an interface that services can implement to provide graceful shutdown capabilities with context support. This allows for timeout and cancellation control during shutdown operations.

The Shutdown method should perform any necessary cleanup and respect the provided context for cancellation and timeout.

Example:

type Server struct {
    srv *http.Server
}

func (s *Server) Shutdown(ctx context.Context) {
    s.srv.Shutdown(ctx)
}

type ShutdownerWithContextAndError ΒΆ

type ShutdownerWithContextAndError interface {
	Shutdown(context.Context) error
}

ShutdownerWithContextAndError is an interface that services can implement to provide graceful shutdown capabilities with both context support and error reporting. This is the most flexible shutdown interface, allowing for timeout control and error reporting.

The Shutdown method should perform any necessary cleanup, respect the provided context for cancellation and timeout, and return an error if the shutdown process fails.

Example:

type Server struct {
    srv *http.Server
}

func (s *Server) Shutdown(ctx context.Context) error {
    return s.srv.Shutdown(ctx)
}

type ShutdownerWithError ΒΆ

type ShutdownerWithError interface {
	Shutdown() error
}

ShutdownerWithError is an interface that services can implement to provide graceful shutdown capabilities with error reporting. This allows services to report any errors that occur during shutdown.

The Shutdown method should perform any necessary cleanup and return an error if the shutdown process fails.

Example:

type Database struct {
    conn *sql.DB
}

func (db *Database) Shutdown() error {
    return db.conn.Close()
}

Directories ΒΆ

Path Synopsis
tests

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL