event hub: a start that found no durable on the bus is tried again at the next start, so a part is not lost for the order in which the bus makes its consumer (B7e; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 15:25:56 +01:00
parent b7f6cd6bf4
commit 4111794690
2 changed files with 37 additions and 12 deletions
+10 -12
View File
@@ -19,11 +19,9 @@ import (
type EventHub struct {
logf func(string, ...any)
mu sync.RWMutex
routes []hubRoute
started bool
cons jetstream.ConsumeContext
startErr error
mu sync.RWMutex
routes []hubRoute
cons jetstream.ConsumeContext
}
type hubRoute struct {
@@ -68,23 +66,23 @@ func (h *EventHub) Patterns() []string {
return out
}
// Start binds the module's durable on the shared events stream and pulls it; later calls do nothing and return the
// first one's result. It makes no stream and no consumer.
// Start binds the module's durable on the shared events stream and pulls it; a call after a start that took does
// nothing. It makes no stream and no consumer: a consumer the bus does not hold yet is the error of this call, and a
// later call (the module's next change of membership) binds it, so a part is not lost for the bus's order.
func (h *EventHub) Start(ctx context.Context, js jetstream.JetStream, cred Account) error {
h.mu.Lock()
defer h.mu.Unlock()
if h.started {
return h.startErr
if h.cons != nil {
return nil
}
h.started = true
cons, err := cred.EventConsumer(ctx, js, EventsStream)
if err == nil {
h.cons, err = HearEvents(cons, h.hear, h.logf)
}
if err != nil {
h.startErr = fmt.Errorf("the consumer %s on %s is not heard: %w", cred.EventConsumerName(), EventsStream, err)
return fmt.Errorf("the consumer %s on %s is not heard: %w", cred.EventConsumerName(), EventsStream, err)
}
return h.startErr
return nil
}
// Stop ends the pull.