Repository navigation
Metadata takes any ordered or bool value, activations run on a worker pool, every container
iterates the same way, and a long list of hook, livelock, pipe and retry fixes.
BREAKING
All() is the one iterator on every container, and it is an iter.Seq. signal.Group,
port.Group, port.Collection, component.Collection, cycle.Group and
ActivationResultCollection all have All() iter.Seq[T]: insertion order on the groups, name order
on the keyed collections. It replaces ForEach, ForEachIf, Each, AllOrdered, the
slice-returning All() on the groups and the map-returning All() on the keyed types.
signal.Group.AllPayloads() becomes Payloads() iter.Seq[any], and cycle.Group gains
ByNumber(n), since with a history limit a cycle's position is not its number.
// before
err := p.Signals().ForEach(func(s *signal.Signal) error { use(s); return nil })
for _, s := range p.Signals().All() { use(s) }
payloads := p.Signals().AllPayloads()
// after
for s := range p.Signals().All() { use(s) } // break, continue and return err work as usual
signals := slices.Collect(p.Signals().All()) // when a slice is needed
for payload := range p.Signals().Payloads() { use(payload) }One vocabulary across groups, collections and activation results.
- Keyed collections (
port.Collection,component.Collection):Any()→First(),
AnyMatch(p)→Any(p),FindAny(p)→Find(p).ActivationResultCollection.FindAny→Find. ActivationResult:ActivationError()→Err(),ActivationErrors()→Errors();
component.IsWaitingForInput(r)andWantsToKeepInputs(r)become the methodsr.IsWaiting()
andr.KeepsInputs().ActivationErrorWithComponentNameis removed.Component.ValidateBeforeAddingToMesh→Validate;PluginRegistered→HasPluginon both
FMeshandComponent.
// before
if result.ActivationError() != nil { ... }
first := fm.Components().Any()
// after
if result.Err() != nil { ... }
first := fm.Components().First()Activation results are built whole. NewActivationResult(name, code, errs...) replaces
NewActivationResult(name) plus SetActivated, SetActivationCode and AddActivationError;
Activated() is derived from the code. ActivationResultCollection.Remove and Clear and
cycle.Group.RemoveOldest are removed.
Collection methods with no caller are gone. Map, MapIf and Without on port.Group,
cycle.Group, port.Collection and component.Collection (their elements are live pointers, so
loop in place; Filter stays); component.Collection.Clear; port.Collection.PutSignalsOnEach,
PipeEachTo and Flush; signal.Group.Reduce, Contains and ContainsPayloadFunc
(ContainsPayload stays); the component.ResultMapper type. The port.Group constructors are
unexported.
WithErrorHandlingStrategy rejects an unknown strategy at New, with
ErrUnsupportedErrorHandlingStrategy, instead of failing a cycle after it has already run.
Added
meta.Valuewidens fromstring | float64tocmp.Ordered | ~bool: a metadata entry can be
int,bool, any sized int, uint or float, or a named type built on one of them, such as
type Celsius float64. The read rule is unchanged: an entry reads back only as the type it was
written with, soSet("n", 3)is read withValue[int], notValue[float64].fmesh.WithMaxConcurrency(n)andfmesh.WithUnlimitedConcurrency(). The ready components of a
cycle share at mostngoroutines (defaultGOMAXPROCS) instead of starting one each, which was
27 % of CPU in the throughput benchmark.
Changed
- A run allocates about half as much (root benchmarks, geomean vs v1.17.0: allocs/op −51 %,
B/op −49 %, time/op −36 %). Building a mesh is linear in the number of components (100k
components in 0.8 s, not 73 s). Run history is released afterRun, and history eviction is O(1). - Observer hooks run every registered hook and join the errors:
AfterRun,AfterCycle,
AfterActivation,OnComponentAdded,OnSignalsDeliveredandOnClear.AfterCycleruns
however the cycle ends, and anAfterRunerror is joined to the run's.Beforehooks,
OnCreation,OnSignalsAddedand the pipe hooks stay fail-fast. AfterRunhooks receive the contextRunwas called with, not the run context that a time
limit has already expired.AddComponentsvalidates the whole batch before adopting any component; a rejected batch
leaves every component where it was.- Errors from
OnClearandOnCreationhooks name the component and port. ActivationResultCollectionis walked in component-name order, and never runs user code under
its lock.
Fixed
- Livelock detection counts a stall from its first stalled cycle, so
WithLivelockThreshold(n)
no longer fires one cycle late, and a waiter that drops its inputs is no longer reported as a
livelock. - A component whose
BeforeActivationhook failed has its inputs cleared, so they no longer pile
up underIgnoreAll. - A pipe whose
OnOutboundPipeorOnInboundPipehook fails is removed again, so a retried
PipeTono longer delivers every signal twice. WithRetry: an output port that was empty before the activation is no longer refilled with an
empty group between attempts; aWithRetryIfbackoff checks the context after waiting; a panic
on a later attempt keeps the errors of the attempts before it.- Adding ports or components is all-or-nothing, also for a duplicate within one call; adding them
one by one is no longer quadratic. - Doc comments, the wiki and the agent docs were checked against the code and corrected.