Skip to content

Add database handler abstractions, registry improvements, and test infrastructure - #233

Merged
RyanTheRobothead merged 15 commits into
unstablefrom
registry_fixes
Mar 9, 2026
Merged

Add database handler abstractions, registry improvements, and test infrastructure#233
RyanTheRobothead merged 15 commits into
unstablefrom
registry_fixes

Conversation

@RyanTheRobothead

@RyanTheRobothead RyanTheRobothead commented Mar 5, 2026

Copy link
Copy Markdown
Member

Summary

  • Database handler abstractions: New madsci.common.db_handlers package with ABCs (MongoHandler, RedisHandler, PostgresHandler, MinioHandler) and both real and in-memory implementations. All 6 database-backed managers accept injectable handler parameters, enabling dependency injection for testing.
  • Registry lock retry + shutdown release: Managers retry lock acquisition on contention (configurable timeout, default 60s) and release the lock via atexit (using weakref to avoid preventing GC). Nodes now resolve stable IDs from the registry at startup using the same IdentityResolver pattern, with explicit close() for notebook users.
  • EventClient retry removal: Removed the async retry queue (background thread, event buffer, OTEL metrics). Event delivery is now synchronous and fire-once, with a new send_failures OTEL counter and structured error logging for failed deliveries.
  • OTEL logging migration: Migrated from deprecated LoggingHandler to LoggingInstrumentor from opentelemetry-instrumentation-logging, with double-instrumentation guard. Eliminates 44+ deprecation warnings.
  • DataManager MinIO consolidation: All MinIO operations now routed through MinioHandler abstraction; removed direct self.minio_client usage. Legacy raw clients are wrapped in RealMinioHandler during setup.
  • Legacy parameter deprecation: Legacy database connection constructor parameters (db_connection, db_client, redis_connection, mongo_connection) now emit DeprecationWarning across all 6 managers and 2 state handlers.
  • Test infrastructure: Isolated test suite from shared registry; replaced pytest-mock-resources with in-memory handlers (no Docker required for most tests); replaced nbconvert with papermill; testcontainer fixtures now skip gracefully when Docker is unavailable; added PortWaitStrategy for macOS host port-forwarding race.

Test plan

  • Run pre-commit checks (just checks)
  • Run full test suite (pytest) — 2677 tests passing
  • Verify all 55 new handler tests pass
  • Verify Configuration.md includes NodeConfig/RestNodeConfig settings
  • Verify CHANGELOG covers all changes
  • Review updated documentation (CLAUDE.md, CHANGELOG, data manager CLAUDE.md)

Developer Checklists

I have:

  • Run Pre-commit and Unit Tests, and ensured that they pass
  • Created or updated documentation relevant to your change
  • Created or updated unit tests relevant to your change

🤖 Generated with Claude Code

@RyanTheRobothead RyanTheRobothead self-assigned this Mar 5, 2026
@RyanTheRobothead
RyanTheRobothead requested a review from Copilot March 5, 2026 23:09
Managers now retry registry lock acquisition on contention (configurable
timeout, default 60s) and release the lock via atexit, fixing identity
loss after ungraceful container restarts. RegistryLockError is fatal.

Nodes now resolve stable IDs from the registry at startup using the same
IdentityResolver pattern, gaining stable identity across restarts
instead of generating a fresh ULID each time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@RyanTheRobothead RyanTheRobothead added bug Something isn't working enhancement New feature or request labels Mar 5, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves registry-based identity stability and startup resilience by adding configurable retry behavior for registry lock contention, releasing locks on shutdown, and extending the same stable-ID resolution pattern to nodes.

Changes:

  • Added retry_timeout support through IdentityResolverLocalRegistryManager.resolve() with retry-on-RegistryLockError.
  • Managers and nodes now release registry identity locks via atexit, and nodes resolve stable IDs at startup (configurable via NodeConfig).
  • Bumped project/package versions to 0.7.1 and updated docs + unit tests accordingly.

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
ui/package.json Bumps UI package version to 0.7.1.
src/madsci_workcell_manager/pyproject.toml Bumps package version to 0.7.1.
src/madsci_squid/pyproject.toml Bumps package version to 0.7.1.
src/madsci_resource_manager/pyproject.toml Bumps package version to 0.7.1.
src/madsci_node_module/tests/test_node_registry.py Adds node identity-resolution unit tests via registry resolver mocking.
src/madsci_node_module/tests/conftest.py Disables registry resolution by default in node tests to avoid shared-lock side effects.
src/madsci_node_module/pyproject.toml Bumps package version to 0.7.1.
src/madsci_node_module/madsci/node_module/abstract_node_module.py Adds node registry identity resolution + atexit lock release.
src/madsci_location_manager/pyproject.toml Bumps package version to 0.7.1.
src/madsci_experiment_manager/pyproject.toml Bumps package version to 0.7.1.
src/madsci_experiment_application/pyproject.toml Bumps package version to 0.7.1.
src/madsci_event_manager/pyproject.toml Bumps package version to 0.7.1.
src/madsci_data_manager/pyproject.toml Bumps package version to 0.7.1.
src/madsci_common/tests/test_registry_resolution.py Updates manager registry-resolution test expectations for retry_timeout.
src/madsci_common/tests/test_registry/test_local_registry.py Adds tests for resolve() retry behavior under lock contention.
src/madsci_common/pyproject.toml Bumps package version to 0.7.1.
src/madsci_common/madsci/common/types/node_types.py Adds node registry-resolution settings fields.
src/madsci_common/madsci/common/types/manager_types.py Adds manager registry_lock_timeout setting.
src/madsci_common/madsci/common/registry/local_registry.py Implements retry loop in resolve() with retry_timeout.
src/madsci_common/madsci/common/registry/identity_resolver.py Plumbs retry_timeout through resolver APIs.
src/madsci_common/madsci/common/manager_base.py Adds manager retry timeout + fatal lock contention + atexit release.
src/madsci_client/pyproject.toml Bumps package version to 0.7.1.
pyproject.toml Bumps monorepo version to 0.7.1.
docs/api/madsci/common/types/node_types.md Documents new NodeConfig registry fields.
docs/api/madsci/common/types/manager_types.md Documents new ManagerSettings.registry_lock_timeout.
docs/api/madsci/common/registry/local_registry.md Documents new retry_timeout parameter on LocalRegistryManager.resolve().
docs/api/madsci/common/registry/index.md Documents retry_timeout in resolver/registry APIs.
docs/api/madsci/common/registry/identity_resolver.md Documents retry_timeout in IdentityResolver APIs.
docs/Configuration.md Adds env var docs for *_REGISTRY_LOCK_TIMEOUT across managers.
docs/CHANGELOG.md Adds 0.7.1 release notes for registry retry + shutdown release + node stability.
.env.example Adds *_REGISTRY_LOCK_TIMEOUT examples for managers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/madsci_common/madsci/common/manager_base.py
Comment thread src/madsci_node_module/madsci/node_module/abstract_node_module.py
Comment thread src/madsci_common/madsci/common/registry/local_registry.py Outdated
Comment thread src/madsci_common/tests/test_registry/test_local_registry.py Outdated
Comment thread src/madsci_node_module/tests/test_node_registry.py Outdated
RyanTheRobothead and others added 4 commits March 6, 2026 10:42
…dundant patches

- Extract hardcoded 2.0s retry interval to RETRY_INTERVAL_SECONDS constant
- Replace sleep-based test coordination with threading.Event for deterministic behavior
- Remove redundant @patch decorators that targeted wrong import path in node registry tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add session-scoped autouse fixture that redirects MADSCI_REGISTRY_PATH to
a temp file and patches enable_registry_resolution defaults to False on
ManagerSettings, NodeConfig, and all their subclasses recursively. This
prevents FileLock contention and heartbeat-thread spawning across 2612
tests.

Key changes:
- conftest.py: _patch_field_default_recursive() walks Pydantic v2
  subclass trees (each has independent FieldInfo copies)
- 18 test files: explicit enable_registry_resolution=False on all
  Settings/Config instantiations (belt-and-suspenders)
- test_registry.py: use env var patching instead of _default_path mock
- test_registry_resolution.py, test_node_registry.py: pass
  enable_registry_resolution=True explicitly in default-assertion tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch from `nbconvert --execute` to `papermill` for validating example
notebooks, gaining per-cell timeouts (120s) and readable log output.
Rename e2e_tests commands to validate_notebooks to clarify intent:
these validate that example notebooks still work, not serve as e2e tests.

- Add close() and __del__() to AbstractNode for registry lock cleanup
- Add __del__() to AbstractManagerBase for GC-based identity release
- Update node_notebook.ipynb to call close() before node reassignment
- Rename Docker service e2e_test_runner -> notebook_validator
- Rename GH Actions workflow and job to "Validate Example Notebooks"
- Regenerate docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Mar 8, 2026

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  src/madsci_client/madsci/client
  event_client.py 172-174, 233-235
  src/madsci_common/madsci/common
  manager_base.py 317-325, 330
  src/madsci_common/madsci/common/db_handlers
  __init__.py
  minio_handler.py 142-151, 196-201, 213, 220-221
  mongo_handler.py 15, 98-99, 112, 138-139
  postgres_handler.py 15, 109-110, 212-213
  redis_handler.py 143-144, 153-155, 159-161, 165-167, 199
  src/madsci_common/madsci/common/local_backends
  inmemory_collection.py 191, 305-308, 327, 331-332, 472, 485, 509-514
  inmemory_redis.py
  src/madsci_common/madsci/common/otel
  bootstrap.py 47-54, 308, 312-314
  src/madsci_common/madsci/common/registry
  identity_resolver.py
  local_registry.py
  src/madsci_common/madsci/common/types
  manager_types.py
  node_types.py
  src/madsci_data_manager/madsci/data_manager
  data_server.py 45, 70, 102-107, 120, 142, 173
  src/madsci_event_manager/madsci/event_manager
  event_server.py 45, 119, 187-194, 448-452
  src/madsci_experiment_manager/madsci/experiment_manager
  experiment_server.py 41, 47, 114-123
  src/madsci_location_manager/madsci/location_manager
  location_server.py 53, 237
  location_state_handler.py 33, 44-47, 58-59, 74, 85-91, 95
  src/madsci_node_module/madsci/node_module
  abstract_node_module.py 235-237, 243, 261-262
  src/madsci_resource_manager/madsci/resource_manager
  database_version_checker.py
  resource_interface.py 90-101, 1575, 1581
  resource_server.py 110-118
  src/madsci_workcell_manager/madsci/workcell_manager
  state_handler.py 50, 56, 70-73, 83, 102-103, 211-214, 455, 459-460
  workcell_server.py 79, 85, 272
Project Total  

This report was generated by python-coverage-comment-action

RyanTheRobothead and others added 6 commits March 7, 2026 20:34
Introduce ABC-based database handler abstractions (MongoHandler,
RedisHandler, PostgresHandler, MinioHandler) with real and in-memory
implementations. Migrate all 6 managers to accept handler parameters,
enabling fast in-memory testing without Docker containers.

Key changes:
- New db_handlers package with ABCs and implementations for all 4 DB types
- All managers accept optional handler params (backward compatible)
- All test suites migrated from pytest-mock-resources to in-memory handlers
- LocalRunner uses handlers instead of raw in-memory clients
- SQLiteHandler handles composite PK autoincrement via raw DDL fallback
- InMemoryCollection gains projection support, replace_one(), client property
- InMemoryRedisDict inherits MutableMapping for Pydantic compatibility
- Fix timezone-naive datetime comparison in ResourceInterface lock checks
- Fix DatabaseVersionChecker to only create SchemaVersionTable (not all tables)
- Remove pytest-mock-resources dependency
- 2677 tests passing (up from 2612), all without Docker

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The testcontainer-based integration fixtures now catch container startup
failures and verify connectivity via ping() before yielding, converting
unreachable containers into clean pytest skips instead of hard failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: PostgresContainer and MongoDbContainer verify readiness
only inside the container (ExecWaitStrategy/log checks), but on
macOS with Rancher Desktop, host-side port forwarding through the VM
networking layer lags ~1-2s behind. Tests connecting immediately after
container "ready" hit connection refused on the mapped host port.

Fix: Add PortWaitStrategy(port).wait_until_ready() calls for Postgres
and MongoDB fixtures to poll the host-side mapped port before yielding
the handler. Redis and MinIO already verify host connectivity (Redis
via client.ping() with retry, MinIO via HttpWaitStrategy).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…on-logging

Replace the deprecated `LoggingHandler` from `opentelemetry.sdk._logs` with
`LoggingInstrumentor` from `opentelemetry-instrumentation-logging`, which
automatically bridges stdlib logging to OTEL log records via the global
LoggerProvider. This eliminates 44 deprecation warnings across 5 test files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@RyanTheRobothead RyanTheRobothead changed the title Add registry lock retry + shutdown release for managers and nodes Add database handler abstractions, registry improvements, and test infrastructure Mar 8, 2026
Expand CHANGELOG to cover all branch changes (db handler abstractions,
EventClient retry removal, OTEL logging migration, test infrastructure,
node lifecycle management). Add NodeConfig/RestNodeConfig to
pydantic-settings-export and regenerate Configuration.md and .env.example.
Fix stale references to pytest-mock-resources and Docker-required tests
across AGENTS.md, CONTRIBUTING.md, guides, and tutorials.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@RyanTheRobothead
RyanTheRobothead changed the base branch from main to unstable March 8, 2026 15:18
RyanTheRobothead and others added 2 commits March 8, 2026 17:00
…ngs, and safety fixes

- Fix DataManager minio handler gap: consolidate all MinIO operations through
  MinioHandler abstraction, removing direct self.minio_client usage
- Add EventClient send_failures OTEL counter and upgrade failure logging to
  error level with structured kwargs (event_type, event_id)
- Add LoggingInstrumentor double-instrumentation guard (is_instrumented check)
- Move EventManager pymongo imports behind TYPE_CHECKING / into methods
- Use weakref-based atexit handlers in managers and nodes to allow GC, with
  _atexit_registered flag to prevent handler accumulation
- Fix InMemoryMongoHandler _client = None when external database provided
- Add TYPE_CHECKING-guarded return types for handler ABCs (Collection, Engine,
  MetaData, MutableMapping, ContextManager)
- Emit DeprecationWarning for legacy constructor params (db_connection,
  db_client, redis_connection, mongo_connection) across all managers
- Update CHANGELOG, data manager docs, auto-generated API docs, and PR body

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
github.repository returns mixed-case (AD-SDL/MADSci) but Docker requires
lowercase repository names. Add a step to lowercase IMAGE_NAME and
DASHBOARD_IMAGE_NAME env vars before they're used in docker pull/tag commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@RyanTheRobothead
RyanTheRobothead merged commit 1d2d12c into unstable Mar 9, 2026
4 checks passed
@RyanTheRobothead
RyanTheRobothead deleted the registry_fixes branch April 9, 2026 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants