refactor(iris): replace LocalController with LocalCluster, decouple from Platform#3632
refactor(iris): replace LocalController with LocalCluster, decouple from Platform#3632
Conversation
…rom Platform Break the circular dependency between controller/local.py and platform/local.py by moving LocalController to a new top-level local_cluster.py module (renamed to LocalCluster). LocalPlatform no longer owns controller lifecycle — callers use LocalCluster directly for local mode. - New: lib/iris/src/iris/cluster/local_cluster.py (LocalCluster + create_local_autoscaler) - Delete: lib/iris/src/iris/cluster/controller/local.py - Simplify: LocalPlatform — remove start/stop/restart_controller, wait_for_controller, auto_login_token - Update: connect_cluster(), CLI cluster start, CLI main, IrisClient, all tests - Fix: stop() → close() in several callers to prevent _db_dir temp dir leaks Closes #3585 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Claude finished @rjpower's task in 1m 30s —— View job PR Review: refactor(iris): replace LocalController with LocalCluster, decouple from Platform
Overall: Clean refactor that breaks a real circular dependency and improves resource cleanup. The rename from Issues Found1.
2.
3. Stale doc reference to
Suggestions (non-blocking)
What looks good
|
|
@claude fix the review issues |
|
Claude finished @rjpower's task in 2m 2s —— View job Fixed review issues
|
…ller refs Fix _db_dir temp directory leaks in test_demo_notebook_submit.py and test_local_cluster.py by using close() instead of stop(). Update stale LocalController references in testing-design.md to LocalCluster. Co-authored-by: Russell Power <rjpower@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
yonromai
left a comment
There was a problem hiding this comment.
🤖 This refactor matches #3585's main goal: it cleanly extracts local-mode orchestration into LocalCluster and removes the circular dependency between LocalPlatform and the old LocalController.
Specification check: the module split and call-site updates follow the issue's proposed architecture, and the earlier stop() -> close() misses were fixed. The remaining regression is that the new LocalCluster(config) entry points no longer preserve the old thread-container isolation, so shutting down a local cluster can now stop unrelated managed threads in the same process.
Generated with Codex
| if is_local: | ||
| from iris.cluster.local_cluster import LocalCluster | ||
|
|
||
| cluster = LocalCluster(config) |
There was a problem hiding this comment.
🤖 This changes local-mode thread ownership in a way that can stop unrelated managed threads in the same process. Before this PR, connect_cluster() went through LocalPlatform.start_controller(), which passed the platform's private ThreadContainer into LocalController. Now LocalCluster(config) is created with threads=None, so Controller/Autoscaler fall back to the ambient default container via get_thread_container(). On shutdown, Controller.stop() -> Autoscaler.shutdown() calls self._threads.stop(), which now stops unrelated threads sharing that container.
I reproduced this directly with a thread_container_scope("probe") probe: on this PR, an unrelated thread is dead after with connect_cluster(...):; on origin/main it stays alive. iris cluster start --local has the same regression for the same reason.
Recommended fix: keep the new LocalCluster split, but preserve the old isolation by creating an explicit ThreadContainer/platform-owned container at these new call sites and passing it into LocalCluster(threads=...).
Generated with Codex
|
@claude can you fix yonromai's issue in a separate PR if you think it's appropraite. turn on automerge, tag yonromai for review |
|
Claude finished @rjpower's task in 6m 20s —— View job • Fix thread container isolation regression in LocalCluster
Created #3637 with automerge enabled and @yonromai requested for review. Fix: Each |
…ites
LocalCluster created with threads=None falls back to the ambient default
ThreadContainer. On shutdown, stopping the controller/autoscaler would
stop unrelated threads sharing that container. Fix by creating a dedicated
ThreadContainer("local-cluster") at each call site.
Fixes the regression identified in #3632 review.
Co-authored-by: Russell Power <rjpower@users.noreply.github.com>
…rom Platform (#3632) - Break circular dependency between `controller/local.py` ↔ `platform/local.py` by moving `LocalController` to a new top-level `local_cluster.py` module (renamed `LocalCluster`) - `LocalPlatform` no longer owns controller lifecycle — callers use `LocalCluster` directly for local mode - Fix `stop()` → `close()` in several callers to prevent `_db_dir` temp directory leaks ## Changes | File | Change | |------|--------| | `cluster/local_cluster.py` | **New** — `LocalCluster` + `create_local_autoscaler` + `make_local_cluster_config` | | `cluster/controller/local.py` | **Deleted** — replaced by `local_cluster.py` | | `cluster/platform/local.py` | Remove `start/stop/restart_controller`, `wait_for_controller`, `auto_login_token`; inline `stop_all` | | `cluster/manager.py` | `connect_cluster()` detects local mode and uses `LocalCluster` directly | | `cli/cluster.py` | `cluster start` uses `LocalCluster` for local mode | | `cli/main.py` | CLI setup uses `LocalCluster`; fix `stop()` → `close()` | | `client/client.py` | Import from new location; fix `stop()` → `close()` | | Tests (4 files) | Update imports `LocalController` → `LocalCluster`; fix `stop()` → `close()` |
Summary
controller/local.py↔platform/local.pyby movingLocalControllerto a new top-levellocal_cluster.pymodule (renamedLocalCluster)LocalPlatformno longer owns controller lifecycle — callers useLocalClusterdirectly for local modestop()→close()in several callers to prevent_db_dirtemp directory leaksChanges
cluster/local_cluster.pyLocalCluster+create_local_autoscaler+make_local_cluster_configcluster/controller/local.pylocal_cluster.pycluster/platform/local.pystart/stop/restart_controller,wait_for_controller,auto_login_token; inlinestop_allcluster/manager.pyconnect_cluster()detects local mode and usesLocalClusterdirectlycli/cluster.pycluster startusesLocalClusterfor local modecli/main.pyLocalCluster; fixstop()→close()client/client.pystop()→close()LocalController→LocalCluster; fixstop()→close()Test plan
uv run pytest lib/iris/tests/ -m "not e2e")./infra/pre-commit.py --all-files --fix)Closes #3585
🤖 Generated with Claude Code