v0.8.0
v0.8.0
Two features and one rule. Explain and Graph render the dependency graph as it
was actually built. Modules compose by Use, with every registration attributed
to the module that made it. And the rule that makes modules safe to compose: a
second registration of a key within one scope must say so with Override(), or
it is rejected naming both sites. That last one is breaking, and the reason for
the minor bump.
go doc -all against v0.7.0 adds Binding.Override, Module, Scope.Use,
Scope.Explain and Scope.Graph, and changes one signature: Test takes
...Module.
Behaviour that can break an upgrade:
-
A duplicate registration of a key within one scope no longer wins silently.
It is rejected at the next resolution, naming both registrations and, when
they came from modules, both modules:di: *app.DB is provided at app.Storage (wire.go:12) and again at
app.Caching (cache.go:8): a second registration of a key must be
marked Override() to replace the firstMark the registration that means to replace the earlier one: for the test
seam, s.Value(&fake).Override(). An Override() with nothing to override in
its scope is rejected too, since a fake for a service that has since been
renamed would otherwise be a registration nobody resolves. A child scope
still shadows its parent without any marker. A key that has served a value
still cannot be replaced at all. -
Test takes ...Module. Function literals and named functions are assignable,
so those calls compile unchanged; a call that spreads a []func(*Scope) with
... needs the slice typed []Module.
Added:
-
Scope.Explain[T] prints the dependency tree of a service as it was built,
with each node's lifetime, scope, lifecycle state and registration site, and
the instances that needed it. Scope.Graph exports everything built as
Graphviz DOT, one cluster per scope. Neither builds anything. The recording
behind them costs nothing on the warm path. -
Module is a named func(*Scope); Scope.Use applies modules in order and
attributes every registration they make -- directly, from a child the module
opens, or later from a constructor the module registered -- to the module's
function name. Event.Module carries the same name to observers.
Fixed:
- A panicking OnDrain or OnStop hook is reported as that hook's failure rather
than propagating out of Stop. The start step was always recovered this way;
the other two were not, so a panic in either abandoned the teardown halfway:
stopOnce claimed and never settled, every later Stop waiting on it until its
context ran out, every instance behind it never released. Found by the
concurrent fuzzer the moment it could build a scope with a permanently
rejected registration -- a drain hook resolving through one meets the
rejection as a panic.
Internal: the machinery the 0.7.0 API cuts left behind is gone. A resolution
path node is 32 bytes rather than 48, so a warm resolve allocates 64 B rather
than 96 B and runs about 8% faster.
Testing: the generators register through Use and carry an override bit, the
property model gained the override rule and was mutation-tested clause by
clause, and generator coverage went from 88.5% to 92.1% with the CI floor
raised to 90.