J2: the tool runner tells a subscribed bundle how its module's consumer stands, as mesh/heartbeat (stdio.OnHeartbeat), at each idle beat and once Missed (ADR 0615, ADR 0621, issue 1966)
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -775,6 +775,7 @@ type consumers struct {
|
||||
type moduleEvents struct {
|
||||
stop func()
|
||||
delivers []*func(json.RawMessage) error
|
||||
beats []*func(json.RawMessage)
|
||||
}
|
||||
|
||||
// stopAll unbinds every module's consumer.
|
||||
@@ -822,6 +823,7 @@ type moduleBus struct {
|
||||
module string
|
||||
mu sync.Mutex
|
||||
deliver *func(json.RawMessage) error
|
||||
beat *func(json.RawMessage)
|
||||
}
|
||||
|
||||
// Publish emits an event as the module (ADR 0193).
|
||||
@@ -859,7 +861,7 @@ func (b *moduleBus) Ask(params json.RawMessage) (json.RawMessage, error) {
|
||||
// Subscribe hands this bundle the module's events. The consumer is bound once per module; each of
|
||||
// the module's children that subscribed is handed every event, and the event is acknowledged only
|
||||
// when all of them took it — one consumer split between two readers would give each half.
|
||||
func (b *moduleBus) Subscribe(deliver func(json.RawMessage) error) error {
|
||||
func (b *moduleBus) Subscribe(deliver func(json.RawMessage) error, beat func(json.RawMessage)) error {
|
||||
b.mu.Lock()
|
||||
if b.deliver == nil {
|
||||
d := deliver
|
||||
@@ -868,6 +870,13 @@ func (b *moduleBus) Subscribe(deliver func(json.RawMessage) error) error {
|
||||
*b.deliver = deliver
|
||||
}
|
||||
mine := b.deliver
|
||||
if b.beat == nil {
|
||||
x := beat
|
||||
b.beat = &x
|
||||
} else {
|
||||
*b.beat = beat
|
||||
}
|
||||
mineBeat := b.beat
|
||||
b.mu.Unlock()
|
||||
|
||||
c := b.all
|
||||
@@ -886,12 +895,14 @@ func (b *moduleBus) Subscribe(deliver func(json.RawMessage) error) error {
|
||||
}
|
||||
if !listed {
|
||||
m.delivers = append(m.delivers, mine)
|
||||
m.beats = append(m.beats, mineBeat)
|
||||
}
|
||||
if m.stop != nil {
|
||||
return nil
|
||||
}
|
||||
module := b.module
|
||||
stop, err := c.conn.ConsumeAs(module, func(env bus.Envelope) error { return c.handOut(module, m, env) })
|
||||
stop, err := c.conn.ConsumeAsBeating(module, func(env bus.Envelope) error { return c.handOut(module, m, env) },
|
||||
func(b bus.Beat) { c.handBeat(m, b) })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -900,6 +911,22 @@ func (b *moduleBus) Subscribe(deliver func(json.RawMessage) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// handBeat hands the word on a module's consumer to every child of the module that subscribed, as an event is.
|
||||
func (c *consumers) handBeat(m *moduleEvents, b bus.Beat) {
|
||||
raw, err := json.Marshal(b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.mu.Lock()
|
||||
targets := append([](*func(json.RawMessage))(nil), m.beats...)
|
||||
c.mu.Unlock()
|
||||
for _, t := range targets {
|
||||
if f := *t; f != nil {
|
||||
f(raw)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// errModuleReloading refuses an event heard by a module's consumer that was stopped for a reload.
|
||||
var errModuleReloading = errors.New("the module's bundle is being loaded again; offered again")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user