detached 818dc48

fix(broker): observe daemons over pooled physical transports

Local and remote observation probes dialed a fresh physical transport on
every probe, so demand-aware re-probing (1s local, 2s remote) and the
local re-probe after a stream completes opened extra daemonmux carriages
next to the pooled one, and every remote probe paid a full SSH/QUIC
bootstrap. Probes now borrow the pool's published transport for the
authenticated identity and exact policy (Pool.SharedPhysical) and dial
only when nothing is pooled or the borrowed transport retired mid-probe.
Borrowing never reserves the entry or refreshes its idle deadline.

Restores TestOfflineBrokerSharedTransportKeepsAttachmentsIndependent,
TestWebGatewayTabsShareOneBrokerWithIndependentStreamsAndServices and
TestWebGatewayTabClosingIsIsolated.
commit
818dc4840f4532a22482c12d83df0adbf1a9bbd5
author
brice · · 2026-09-22 20:33 UTC
parent
9e386a7
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
5 files · +205 -4
M internal/app/broker_offline.go +9 -0
@@ -433,6 +433,15 @@ func runBrokerServe(ctx context.Context, options brokerServeOptions, deps broker
433433 if err != nil {
434434 return err
435435 }
436+ // Observation borrows pooled transports rather than dialing its own.
437+ if concreteRemoteProbe != nil {
438+ concreteRemoteProbe.shared.share(pool)
439+ }
440+ if registryConfig.Local != nil {
441+ if local, ok := registryConfig.Local.Probe.(*localRouteProbe); ok {
442+ local.shared.share(pool)
443+ }
444+ }
436445 if err := supervisor.RegisterCloseable("pool", pool); err != nil {
437446 return err
438447 }
@@ -433,6 +433,15 @@ func runBrokerServe(ctx context.Context, options brokerServeOptions, deps broker
433 if err != nil {433 if err != nil {
434 return err434 return err
435 }435 }
436+ // Observation borrows pooled transports rather than dialing its own.
437+ if concreteRemoteProbe != nil {
438+ concreteRemoteProbe.shared.share(pool)
439+ }
440+ if registryConfig.Local != nil {
441+ if local, ok := registryConfig.Local.Probe.(*localRouteProbe); ok {
442+ local.shared.share(pool)
443+ }
444+ }
436 if err := supervisor.RegisterCloseable("pool", pool); err != nil {445 if err := supervisor.RegisterCloseable("pool", pool); err != nil {
437 return err446 return err
438 }447 }
M internal/app/broker_offline_local.go +11 -4
@@ -59,6 +59,7 @@ type localRouteProbe struct {
5959 policy ports.BrokerPolicy
6060 loadIdentity localIdentityLoader
6161 connector ports.BrokerEndpointConnector
62+ shared pooledPhysicals
6263 }
6364
6465 var _ broker.LocalProbe = (*localRouteProbe)(nil)
@@ -152,6 +153,16 @@ func (p *localRouteProbe) ProbeLocal(ctx context.Context) (ports.BrokerDaemonObs
152153 if err := endpoint.Validate(); err != nil {
153154 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, fmt.Errorf("vev: broker local probe: %w", err)
154155 }
156+ request, err := p.request()
157+ if err != nil {
158+ return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err
159+ }
160+ if observation, handled, err := p.shared.observe(ctx, identity, p.policy, request); handled {
161+ if err != nil {
162+ return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err
163+ }
164+ return observation, nil
165+ }
155166 physical, err := p.connector.Connect(ctx, endpoint)
156167 if err != nil {
157168 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err
@@ -163,10 +174,6 @@ func (p *localRouteProbe) ProbeLocal(ctx context.Context) (ports.BrokerDaemonObs
163174 if physical.Identity() != endpoint.ExpectedIdentity.Identity || !physical.Policy().Compatible(endpoint.Policy) {
164175 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, errors.New("vev: broker local probe authenticated binding mismatch")
165176 }
166- request, err := p.request()
167- if err != nil {
168- return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err
169- }
170177 observation, err := observeDaemonCatalogue(ctx, physical, request)
171178 if err != nil {
172179 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err
@@ -59,6 +59,7 @@ type localRouteProbe struct {
59 policy ports.BrokerPolicy59 policy ports.BrokerPolicy
60 loadIdentity localIdentityLoader60 loadIdentity localIdentityLoader
61 connector ports.BrokerEndpointConnector61 connector ports.BrokerEndpointConnector
62+ shared pooledPhysicals
62 }63 }
63 64
64 var _ broker.LocalProbe = (*localRouteProbe)(nil)65 var _ broker.LocalProbe = (*localRouteProbe)(nil)
@@ -152,6 +153,16 @@ func (p *localRouteProbe) ProbeLocal(ctx context.Context) (ports.BrokerDaemonObs
152 if err := endpoint.Validate(); err != nil {153 if err := endpoint.Validate(); err != nil {
153 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, fmt.Errorf("vev: broker local probe: %w", err)154 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, fmt.Errorf("vev: broker local probe: %w", err)
154 }155 }
156+ request, err := p.request()
157+ if err != nil {
158+ return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err
159+ }
160+ if observation, handled, err := p.shared.observe(ctx, identity, p.policy, request); handled {
161+ if err != nil {
162+ return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err
163+ }
164+ return observation, nil
165+ }
155 physical, err := p.connector.Connect(ctx, endpoint)166 physical, err := p.connector.Connect(ctx, endpoint)
156 if err != nil {167 if err != nil {
157 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err168 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err
@@ -163,10 +174,6 @@ func (p *localRouteProbe) ProbeLocal(ctx context.Context) (ports.BrokerDaemonObs
163 if physical.Identity() != endpoint.ExpectedIdentity.Identity || !physical.Policy().Compatible(endpoint.Policy) {174 if physical.Identity() != endpoint.ExpectedIdentity.Identity || !physical.Policy().Compatible(endpoint.Policy) {
164 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, errors.New("vev: broker local probe authenticated binding mismatch")175 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, errors.New("vev: broker local probe authenticated binding mismatch")
165 }176 }
166- request, err := p.request()
167- if err != nil {
168- return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err
169- }
170 observation, err := observeDaemonCatalogue(ctx, physical, request)177 observation, err := observeDaemonCatalogue(ctx, physical, request)
171 if err != nil {178 if err != nil {
172 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err179 return ports.BrokerDaemonObservation{Availability: domain.RemoteAvailabilityUnreachable}, err
M internal/app/broker_remote_probe.go +47 -0
@@ -7,6 +7,7 @@ import (
77 "encoding/json"
88 "errors"
99 "fmt"
10+ "sync/atomic"
1011
1112 "github.com/bnema/vev/internal/domain"
1213 "github.com/bnema/vev/internal/ports"
@@ -34,6 +35,44 @@ type brokerRemoteProbe struct {
3435 binder ports.BrokerIdentityBinder
3536 connector ports.BrokerEndpointConnector
3637 hosts ports.BrokerHostAuthorityReader
38+ shared pooledPhysicals
39+}
40+
41+// sharedPhysicals lends the pooled transport of an attached or warm daemon.
42+type sharedPhysicals interface {
43+ SharedPhysical(ports.BrokerDaemonIdentity, ports.BrokerPolicy) (ports.BrokerPhysicalConnection, bool)
44+}
45+
46+// pooledPhysicals lets an observation probe borrow the broker pool's physical
47+// transport instead of dialing (and, for a remote, bootstrapping SSH/QUIC)
48+// again: the broker exists to share connections. The pool is published after
49+// composition because it binds identities through the registry that runs the
50+// probes. A probe dials only when nothing is pooled, or when the borrowed
51+// transport retired under it.
52+type pooledPhysicals struct{ pool atomic.Value }
53+
54+func (s *pooledPhysicals) share(pool sharedPhysicals) { s.pool.Store(pool) }
55+
56+// observe reports handled=false when the probe must dial its own transport.
57+func (s *pooledPhysicals) observe(ctx context.Context, identity ports.BrokerDaemonIdentity, policy ports.BrokerPolicy, request ports.BrokerOpenStreamRequest) (ports.BrokerDaemonObservation, bool, error) {
58+ pool, _ := s.pool.Load().(sharedPhysicals)
59+ if pool == nil || identity == "" {
60+ return ports.BrokerDaemonObservation{}, false, nil
61+ }
62+ physical, ok := pool.SharedPhysical(identity, policy)
63+ if !ok {
64+ return ports.BrokerDaemonObservation{}, false, nil
65+ }
66+ observation, err := observeDaemonCatalogue(ctx, physical, request)
67+ if err == nil || ctx.Err() != nil {
68+ return observation, true, err
69+ }
70+ select {
71+ case <-physical.Done():
72+ return ports.BrokerDaemonObservation{}, false, nil
73+ default:
74+ return observation, true, err
75+ }
3776 }
3877
3978 var _ ports.BrokerHostProbe = (*brokerRemoteProbe)(nil)
@@ -50,6 +89,14 @@ func (p *brokerRemoteProbe) Probe(ctx context.Context, registration domain.Remot
5089 if err != nil {
5190 return ports.BrokerDaemonObservation{}, err
5291 }
92+ // Borrow the pooled transport of an attached or warm daemon instead of
93+ // bootstrapping SSH/QUIC again. A borrowed transport that retires mid-probe
94+ // falls back to a fresh dial.
95+ if endpoint.ExpectedIdentity.Bound {
96+ if observation, handled, err := p.shared.observe(ctx, endpoint.ExpectedIdentity.Identity, endpoint.Policy, request); handled {
97+ return observation, err
98+ }
99+ }
53100 physical, err := p.connector.Connect(ctx, endpoint)
54101 if err != nil {
55102 return ports.BrokerDaemonObservation{}, err
@@ -7,6 +7,7 @@ import (
7 "encoding/json"7 "encoding/json"
8 "errors"8 "errors"
9 "fmt"9 "fmt"
10+ "sync/atomic"
10 11
11 "github.com/bnema/vev/internal/domain"12 "github.com/bnema/vev/internal/domain"
12 "github.com/bnema/vev/internal/ports"13 "github.com/bnema/vev/internal/ports"
@@ -34,6 +35,44 @@ type brokerRemoteProbe struct {
34 binder ports.BrokerIdentityBinder35 binder ports.BrokerIdentityBinder
35 connector ports.BrokerEndpointConnector36 connector ports.BrokerEndpointConnector
36 hosts ports.BrokerHostAuthorityReader37 hosts ports.BrokerHostAuthorityReader
38+ shared pooledPhysicals
39+}
40+
41+// sharedPhysicals lends the pooled transport of an attached or warm daemon.
42+type sharedPhysicals interface {
43+ SharedPhysical(ports.BrokerDaemonIdentity, ports.BrokerPolicy) (ports.BrokerPhysicalConnection, bool)
44+}
45+
46+// pooledPhysicals lets an observation probe borrow the broker pool's physical
47+// transport instead of dialing (and, for a remote, bootstrapping SSH/QUIC)
48+// again: the broker exists to share connections. The pool is published after
49+// composition because it binds identities through the registry that runs the
50+// probes. A probe dials only when nothing is pooled, or when the borrowed
51+// transport retired under it.
52+type pooledPhysicals struct{ pool atomic.Value }
53+
54+func (s *pooledPhysicals) share(pool sharedPhysicals) { s.pool.Store(pool) }
55+
56+// observe reports handled=false when the probe must dial its own transport.
57+func (s *pooledPhysicals) observe(ctx context.Context, identity ports.BrokerDaemonIdentity, policy ports.BrokerPolicy, request ports.BrokerOpenStreamRequest) (ports.BrokerDaemonObservation, bool, error) {
58+ pool, _ := s.pool.Load().(sharedPhysicals)
59+ if pool == nil || identity == "" {
60+ return ports.BrokerDaemonObservation{}, false, nil
61+ }
62+ physical, ok := pool.SharedPhysical(identity, policy)
63+ if !ok {
64+ return ports.BrokerDaemonObservation{}, false, nil
65+ }
66+ observation, err := observeDaemonCatalogue(ctx, physical, request)
67+ if err == nil || ctx.Err() != nil {
68+ return observation, true, err
69+ }
70+ select {
71+ case <-physical.Done():
72+ return ports.BrokerDaemonObservation{}, false, nil
73+ default:
74+ return observation, true, err
75+ }
37 }76 }
38 77
39 var _ ports.BrokerHostProbe = (*brokerRemoteProbe)(nil)78 var _ ports.BrokerHostProbe = (*brokerRemoteProbe)(nil)
@@ -50,6 +89,14 @@ func (p *brokerRemoteProbe) Probe(ctx context.Context, registration domain.Remot
50 if err != nil {89 if err != nil {
51 return ports.BrokerDaemonObservation{}, err90 return ports.BrokerDaemonObservation{}, err
52 }91 }
92+ // Borrow the pooled transport of an attached or warm daemon instead of
93+ // bootstrapping SSH/QUIC again. A borrowed transport that retires mid-probe
94+ // falls back to a fresh dial.
95+ if endpoint.ExpectedIdentity.Bound {
96+ if observation, handled, err := p.shared.observe(ctx, endpoint.ExpectedIdentity.Identity, endpoint.Policy, request); handled {
97+ return observation, err
98+ }
99+ }
53 physical, err := p.connector.Connect(ctx, endpoint)100 physical, err := p.connector.Connect(ctx, endpoint)
54 if err != nil {101 if err != nil {
55 return ports.BrokerDaemonObservation{}, err102 return ports.BrokerDaemonObservation{}, err
A internal/app/broker_remote_probe_shared_test.go +110 -0
@@ -0,0 +1,110 @@
1+package app
2+
3+import (
4+ "context"
5+ "errors"
6+ "testing"
7+
8+ "github.com/bnema/vev/internal/domain"
9+ "github.com/bnema/vev/internal/ports"
10+ portsmocks "github.com/bnema/vev/internal/ports/mocks"
11+ "github.com/bnema/vev/internal/protocol"
12+ "github.com/stretchr/testify/mock"
13+ "github.com/stretchr/testify/require"
14+)
15+
16+// sharedPhysicalsFunc adapts a closure to the probe's pool lending seam.
17+type sharedPhysicalsFunc func(ports.BrokerDaemonIdentity, ports.BrokerPolicy) (ports.BrokerPhysicalConnection, bool)
18+
19+func (f sharedPhysicalsFunc) SharedPhysical(identity ports.BrokerDaemonIdentity, policy ports.BrokerPolicy) (ports.BrokerPhysicalConnection, bool) {
20+ return f(identity, policy)
21+}
22+
23+// TestBrokerRemoteProbeBorrowsWarmTransport proves observation reuses the
24+// broker pool's attached or warm transport instead of bootstrapping SSH/QUIC
25+// again, and redials only when the borrowed transport has retired.
26+func TestBrokerRemoteProbeBorrowsWarmTransport(t *testing.T) {
27+ registration := domain.RemoteRegistration{Endpoint: "user@example.test", Incarnation: [16]byte{1}, Generation: 1}
28+ policy := remoteBrokerPolicy("quic")
29+ const identity ports.BrokerDaemonIdentity = "remote-daemon"
30+ dialErr := errors.New("dial refused")
31+ tests := []struct {
32+ name string
33+ bound bool
34+ shared bool
35+ openErr error
36+ retired bool
37+ wantDials int
38+ wantErr error
39+ }{
40+ {name: "warm transport observes without dialing", bound: true, shared: true},
41+ {name: "unbound identity dials", bound: false, shared: true, wantDials: 1, wantErr: dialErr},
42+ {name: "no pooled transport dials", bound: true, wantDials: 1, wantErr: dialErr},
43+ {name: "live transport refusal is reported without redial", bound: true, shared: true, openErr: errors.New("stream refused")},
44+ {name: "retired transport redials", bound: true, shared: true, openErr: errors.New("physical closed"), retired: true, wantDials: 1, wantErr: dialErr},
45+ }
46+ for _, tt := range tests {
47+ t.Run(tt.name, func(t *testing.T) {
48+ record := ports.BrokerHostRecord{Registration: registration, Policy: policy}
49+ if tt.bound {
50+ record.Identity = identity
51+ }
52+ routes := portsmocks.NewMockBrokerRouteAuthority(t)
53+ routes.EXPECT().ResolveDialTarget(mock.Anything, mock.Anything).Return(ports.BrokerDialTarget{
54+ Fence: ports.BrokerEndpointFence{Registration: registration}, Policy: policy, Address: "opaque", StartMode: ports.BrokerDaemonExistingOnly,
55+ ExpectedIdentity: ports.BrokerExpectedIdentity{Identity: record.Identity, Bound: tt.bound},
56+ }, nil)
57+ connector := portsmocks.NewMockBrokerEndpointConnector(t)
58+ if tt.wantDials > 0 {
59+ connector.EXPECT().Connect(mock.Anything, mock.Anything).Return(nil, dialErr).Times(tt.wantDials)
60+ }
61+ physical := portsmocks.NewMockBrokerPhysicalConnection(t)
62+ done := make(chan struct{})
63+ if tt.retired {
64+ close(done)
65+ }
66+ if tt.bound && tt.shared {
67+ if tt.openErr != nil {
68+ physical.EXPECT().OpenStream(mock.Anything, mock.Anything).Return(nil, tt.openErr)
69+ physical.EXPECT().Done().Return(done)
70+ } else {
71+ logical := portsmocks.NewMockBrokerLogicalConnection(t)
72+ var sent protocol.CommandRequest
73+ logical.EXPECT().SendClient(mock.Anything).RunAndReturn(func(message protocol.ClientMessage) error {
74+ sent = message.(protocol.CommandRequest)
75+ return nil
76+ })
77+ logical.EXPECT().ReceiveServer().RunAndReturn(func() (protocol.ServerMessage, error) {
78+ return protocol.CommandResult{RequestID: sent.RequestID, Outcome: protocol.CommandSucceeded, Output: testLocalCatalogue(t)}, nil
79+ })
80+ logical.EXPECT().Close().Return(nil)
81+ physical.EXPECT().OpenStream(mock.Anything, mock.Anything).Return(logical, nil)
82+ physical.EXPECT().Identity().Return(identity)
83+ physical.EXPECT().Incarnation().Return(ports.BrokerDaemonIncarnation{1})
84+ }
85+ }
86+ probe := &brokerRemoteProbe{
87+ epoch: 7, routes: routes, binder: portsmocks.NewMockBrokerIdentityBinder(t), connector: connector,
88+ hosts: &routeTestHosts{record: record, found: true},
89+ }
90+ probe.shared.share(sharedPhysicalsFunc(func(gotIdentity ports.BrokerDaemonIdentity, gotPolicy ports.BrokerPolicy) (ports.BrokerPhysicalConnection, bool) {
91+ if !tt.shared || gotIdentity != identity || gotPolicy != policy {
92+ return nil, false
93+ }
94+ return physical, true
95+ }))
96+
97+ observation, err := probe.Probe(context.Background(), registration)
98+ switch {
99+ case tt.wantErr != nil:
100+ require.ErrorIs(t, err, tt.wantErr)
101+ case tt.openErr != nil:
102+ require.ErrorIs(t, err, tt.openErr)
103+ default:
104+ require.NoError(t, err)
105+ require.Equal(t, identity, observation.Identity)
106+ require.True(t, observation.InventoryKnown)
107+ }
108+ })
109+ }
110+}
@@ -0,0 +1,110 @@
1+package app
2+
3+import (
4+ "context"
5+ "errors"
6+ "testing"
7+
8+ "github.com/bnema/vev/internal/domain"
9+ "github.com/bnema/vev/internal/ports"
10+ portsmocks "github.com/bnema/vev/internal/ports/mocks"
11+ "github.com/bnema/vev/internal/protocol"
12+ "github.com/stretchr/testify/mock"
13+ "github.com/stretchr/testify/require"
14+)
15+
16+// sharedPhysicalsFunc adapts a closure to the probe's pool lending seam.
17+type sharedPhysicalsFunc func(ports.BrokerDaemonIdentity, ports.BrokerPolicy) (ports.BrokerPhysicalConnection, bool)
18+
19+func (f sharedPhysicalsFunc) SharedPhysical(identity ports.BrokerDaemonIdentity, policy ports.BrokerPolicy) (ports.BrokerPhysicalConnection, bool) {
20+ return f(identity, policy)
21+}
22+
23+// TestBrokerRemoteProbeBorrowsWarmTransport proves observation reuses the
24+// broker pool's attached or warm transport instead of bootstrapping SSH/QUIC
25+// again, and redials only when the borrowed transport has retired.
26+func TestBrokerRemoteProbeBorrowsWarmTransport(t *testing.T) {
27+ registration := domain.RemoteRegistration{Endpoint: "user@example.test", Incarnation: [16]byte{1}, Generation: 1}
28+ policy := remoteBrokerPolicy("quic")
29+ const identity ports.BrokerDaemonIdentity = "remote-daemon"
30+ dialErr := errors.New("dial refused")
31+ tests := []struct {
32+ name string
33+ bound bool
34+ shared bool
35+ openErr error
36+ retired bool
37+ wantDials int
38+ wantErr error
39+ }{
40+ {name: "warm transport observes without dialing", bound: true, shared: true},
41+ {name: "unbound identity dials", bound: false, shared: true, wantDials: 1, wantErr: dialErr},
42+ {name: "no pooled transport dials", bound: true, wantDials: 1, wantErr: dialErr},
43+ {name: "live transport refusal is reported without redial", bound: true, shared: true, openErr: errors.New("stream refused")},
44+ {name: "retired transport redials", bound: true, shared: true, openErr: errors.New("physical closed"), retired: true, wantDials: 1, wantErr: dialErr},
45+ }
46+ for _, tt := range tests {
47+ t.Run(tt.name, func(t *testing.T) {
48+ record := ports.BrokerHostRecord{Registration: registration, Policy: policy}
49+ if tt.bound {
50+ record.Identity = identity
51+ }
52+ routes := portsmocks.NewMockBrokerRouteAuthority(t)
53+ routes.EXPECT().ResolveDialTarget(mock.Anything, mock.Anything).Return(ports.BrokerDialTarget{
54+ Fence: ports.BrokerEndpointFence{Registration: registration}, Policy: policy, Address: "opaque", StartMode: ports.BrokerDaemonExistingOnly,
55+ ExpectedIdentity: ports.BrokerExpectedIdentity{Identity: record.Identity, Bound: tt.bound},
56+ }, nil)
57+ connector := portsmocks.NewMockBrokerEndpointConnector(t)
58+ if tt.wantDials > 0 {
59+ connector.EXPECT().Connect(mock.Anything, mock.Anything).Return(nil, dialErr).Times(tt.wantDials)
60+ }
61+ physical := portsmocks.NewMockBrokerPhysicalConnection(t)
62+ done := make(chan struct{})
63+ if tt.retired {
64+ close(done)
65+ }
66+ if tt.bound && tt.shared {
67+ if tt.openErr != nil {
68+ physical.EXPECT().OpenStream(mock.Anything, mock.Anything).Return(nil, tt.openErr)
69+ physical.EXPECT().Done().Return(done)
70+ } else {
71+ logical := portsmocks.NewMockBrokerLogicalConnection(t)
72+ var sent protocol.CommandRequest
73+ logical.EXPECT().SendClient(mock.Anything).RunAndReturn(func(message protocol.ClientMessage) error {
74+ sent = message.(protocol.CommandRequest)
75+ return nil
76+ })
77+ logical.EXPECT().ReceiveServer().RunAndReturn(func() (protocol.ServerMessage, error) {
78+ return protocol.CommandResult{RequestID: sent.RequestID, Outcome: protocol.CommandSucceeded, Output: testLocalCatalogue(t)}, nil
79+ })
80+ logical.EXPECT().Close().Return(nil)
81+ physical.EXPECT().OpenStream(mock.Anything, mock.Anything).Return(logical, nil)
82+ physical.EXPECT().Identity().Return(identity)
83+ physical.EXPECT().Incarnation().Return(ports.BrokerDaemonIncarnation{1})
84+ }
85+ }
86+ probe := &brokerRemoteProbe{
87+ epoch: 7, routes: routes, binder: portsmocks.NewMockBrokerIdentityBinder(t), connector: connector,
88+ hosts: &routeTestHosts{record: record, found: true},
89+ }
90+ probe.shared.share(sharedPhysicalsFunc(func(gotIdentity ports.BrokerDaemonIdentity, gotPolicy ports.BrokerPolicy) (ports.BrokerPhysicalConnection, bool) {
91+ if !tt.shared || gotIdentity != identity || gotPolicy != policy {
92+ return nil, false
93+ }
94+ return physical, true
95+ }))
96+
97+ observation, err := probe.Probe(context.Background(), registration)
98+ switch {
99+ case tt.wantErr != nil:
100+ require.ErrorIs(t, err, tt.wantErr)
101+ case tt.openErr != nil:
102+ require.ErrorIs(t, err, tt.openErr)
103+ default:
104+ require.NoError(t, err)
105+ require.Equal(t, identity, observation.Identity)
106+ require.True(t, observation.InventoryKnown)
107+ }
108+ })
109+ }
110+}
M internal/usecase/broker/pool.go +28 -0
@@ -428,6 +428,34 @@ retire:
428428 p.mu.Unlock()
429429 }
430430
431+// SharedPhysical returns the published physical transport the pool holds for
432+// one authenticated identity and exact policy, active or warm, without
433+// reserving it. Observation borrows it to avoid a second bootstrap; the
434+// borrower must not close it and must tolerate its retirement at any time.
435+// Borrowing never refreshes warm order or the idle deadline.
436+func (p *Pool) SharedPhysical(identity ports.BrokerDaemonIdentity, policy ports.BrokerPolicy) (ports.BrokerPhysicalConnection, bool) {
437+ p.mu.Lock()
438+ defer p.mu.Unlock()
439+ e := p.entries[poolKey{identity: identity, policy: policy}]
440+ if p.closed || e == nil || e.retiring || e.redirect != nil {
441+ return nil, false
442+ }
443+ select {
444+ case <-e.ready:
445+ default:
446+ return nil, false
447+ }
448+ if e.err != nil || nilDependency(e.physical) {
449+ return nil, false
450+ }
451+ select {
452+ case <-e.physical.Done():
453+ return nil, false
454+ default:
455+ }
456+ return e.physical, true
457+}
458+
431459 // Close cancels pending operations, closes transports, and joins all owned
432460 // workers. Bounded completion depends on the explicit cancellation/Close port
433461 // contract; callers must not supply adapters that ignore it.
@@ -428,6 +428,34 @@ retire:
428 p.mu.Unlock()428 p.mu.Unlock()
429 }429 }
430 430
431+// SharedPhysical returns the published physical transport the pool holds for
432+// one authenticated identity and exact policy, active or warm, without
433+// reserving it. Observation borrows it to avoid a second bootstrap; the
434+// borrower must not close it and must tolerate its retirement at any time.
435+// Borrowing never refreshes warm order or the idle deadline.
436+func (p *Pool) SharedPhysical(identity ports.BrokerDaemonIdentity, policy ports.BrokerPolicy) (ports.BrokerPhysicalConnection, bool) {
437+ p.mu.Lock()
438+ defer p.mu.Unlock()
439+ e := p.entries[poolKey{identity: identity, policy: policy}]
440+ if p.closed || e == nil || e.retiring || e.redirect != nil {
441+ return nil, false
442+ }
443+ select {
444+ case <-e.ready:
445+ default:
446+ return nil, false
447+ }
448+ if e.err != nil || nilDependency(e.physical) {
449+ return nil, false
450+ }
451+ select {
452+ case <-e.physical.Done():
453+ return nil, false
454+ default:
455+ }
456+ return e.physical, true
457+}
458+
431 // Close cancels pending operations, closes transports, and joins all owned459 // Close cancels pending operations, closes transports, and joins all owned
432 // workers. Bounded completion depends on the explicit cancellation/Close port460 // workers. Bounded completion depends on the explicit cancellation/Close port
433 // contract; callers must not supply adapters that ignore it.461 // contract; callers must not supply adapters that ignore it.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close