Skip to content

feat: infrastructure connectors with lifecycle management#18

Open
case-zbz wants to merge 4 commits intomainfrom
feat/infrastructure-connectors
Open

feat: infrastructure connectors with lifecycle management#18
case-zbz wants to merge 4 commits intomainfrom
feat/infrastructure-connectors

Conversation

@case-zbz
Copy link
Copy Markdown

Summary

  • Added Connect[T] — creates infrastructure clients via factory, registers with slush, emits capitan signals, tracks io.Closer for shutdown
  • Service.Shutdown now closes infrastructure in reverse connection order with signal emission
  • New signals: SignalConnected, SignalDisconnected with KeyConnectorName, KeyConnectorType, KeyConnectorError field keys

Part 2 of #14 — infrastructure connectors.

Test plan

  • Connect registers client with slush, retrievable via Use
  • Factory errors wrapped with connector name
  • io.Closer clients tracked, non-Closer clients skipped
  • SignalConnected emitted on successful connect
  • Shutdown closes in reverse connection order with SignalDisconnected
  • Shutdown with no closers works cleanly
  • Full test suite passes (unit + integration)

🤖 Generated with Claude Code

Connect[T] creates infrastructure clients via factory, registers with
slush, emits capitan signals, and tracks io.Closer instances. Shutdown
closes infrastructure in reverse connection order with signal emission.

Part 2 of #14 — infrastructure connectors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
wintermute-zbz
wintermute-zbz previously approved these changes Mar 28, 2026
Copy link
Copy Markdown
Contributor

@wintermute-zbz wintermute-zbz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — #18

Verdict: APPROVE

Connect[T] with lifecycle management. Reverse-order shutdown. Capitan signal emission.

Findings

service.go:130-145 — closer errors are signaled but not returned.
During shutdown, Close() failures emit capitan.Error signals but don't propagate to the caller. Only the engine shutdown error returns. For graceful shutdown this is defensible — the process is exiting, observability matters more than propagation. But if a caller ever needs to know whether cleanup succeeded, they have no way to find out. Consider errors.Join. Non-blocking — design call.

connector_test.go:159,189time.Sleep(100ms) for server readiness.
Inherently racy. Works in practice because rocco.Engine.Start binds before blocking. A ready-channel would be deterministic. Non-blocking — low probability.

Assessment

  • Shutdown order correct: stop accepting requests, then close infrastructure in reverse order.
  • svc() panic in Connect consistent with existing singleton pattern.
  • Closer slice copied under RLock, iterated outside lock. No lock held during slow I/O.
  • io.Closer detection via type assertion is correct for generics.
  • Reset correctly nils closers slice.
  • No new dependencies — capitan already in go.mod.
  • Test coverage thorough: connect, factory error, closer tracking, no-closer exclusion, signal emission, reverse-order shutdown, empty shutdown.

Clean.

Comment thread connector.go Outdated
Register[T](k, client)
capitan.Info(ctx, SignalConnected,
KeyConnectorName.Field(name),
KeyConnectorType.Field(reflect.TypeOf(client).String()),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same concern as the other PR - reflection should pass through sentinel so we capture metadata. it may even already exist - use sentinel.Inspect

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — using sentinel.TryInspectT with reflect fallback for non-struct types. Connect's T can be interfaces or pointers to external structs, so TryInspect is the safe variant here.

Replaces reflect.TypeOf(client).String() with sentinel.TryInspect[T]()
for struct types, falling back to reflect for non-structs. Consistent
with the sentinel-first approach across sum.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
wintermute-zbz
wintermute-zbz previously approved these changes Mar 28, 2026
Copy link
Copy Markdown
Contributor

@wintermute-zbz wintermute-zbz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — #18

Verdict: APPROVE

New commit adds sentinel.TryInspect[T]() with reflect.TypeOf fallback for connector type metadata. Right call — Connect[T] accepts external types (database drivers, etc.) that sentinel may not have metadata for, unlike Config[T] which only works with user-defined structs.

reflect import remains (needed for the fallback). Previous findings unchanged. Tests pass.

reflect import was unnecessary — sentinel.TryInspect covers structs,
connector name covers everything else.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reorder namedCloser and Service fields to minimize pointer bytes
scanned by GC.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@zoobzio zoobzio self-requested a review March 28, 2026 06:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants