-
Notifications
You must be signed in to change notification settings - Fork 19
feat : add Parallel Task Execution for Multi-Step Installs #288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a dependency-aware asyncio-based parallel installer and a CLI flag Changes
Sequence Diagram(s)sequenceDiagram
actor User as CLI User
participant CLI as cortex/cli.py\n(CortexCLI.install)
participant Parallel as cortex/install_parallel.py\n(run_parallel_install)
participant Scheduler as Scheduler\n(task graph)
participant Worker as Worker\n(threadpool subprocess)
participant Log as Log Callback
User->>CLI: run "cortex install --parallel"
CLI->>CLI: parse args, build commands/descriptions
CLI->>Parallel: run_parallel_install(commands, descriptions, deps)
Parallel->>Scheduler: build task graph & validate commands
loop while tasks remain
Scheduler->>Scheduler: select ready tasks (deps satisfied)
par execute ready tasks
Scheduler->>Worker: schedule run_single_task(task)
Worker->>Log: emit "Starting task"
Worker->>Worker: execute subprocess (threadpool, timeout)
Worker->>Log: emit "Finished/Failed task"
Worker->>Scheduler: report status (SUCCESS/FAILED)
end
alt failure + stop_on_error
Scheduler->>Scheduler: mark dependents SKIPPED
end
end
Parallel->>CLI: return (all_success, tasks[])
CLI->>User: print summary, exit code
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (5)
tests/installer/test_parallel_install.py (2)
16-24: Consider usingsys.executableinstead of hard-codedpythonThese tests shell out to
"python -c ...", which can be brittle on systems where the interpreter is only exposed aspython3or via a venv path. Usingsys.executable(quoted appropriately) would make the tests more robust across environments. Same applies to other commands in this file.
236-257: Unusedtasksvariable in log callback testIn
test_log_callback_called, the unpackedtasksresult is never used:success, tasks = await run_parallel_install(...)This triggers Ruff/Sonar warnings. Rename to
_tasksor_to signal intentional discard:- success, tasks = await run_parallel_install( + success, _tasks = await run_parallel_install( commands, timeout=10, log_callback=log_callback )cortex/cli.py (1)
115-301:CortexCLI.installis very large; consider extracting helpersStatic analysis flags very high cognitive complexity here. The method now handles:
- Validation, API key selection, and interpreter setup
- History bookkeeping
- Dry-run vs execute
- Sequential and parallel execution flows, each with their own logging and error handling
Longer term, consider splitting into helpers (e.g.
_plan_install,_run_parallel,_run_sequential) to make future changes around dependency-aware parallelism less painful.cortex/install_parallel.py (2)
73-81: Minor: static f-string for error messagetask.error = f"Command blocked: matches dangerous pattern"Since there are no placeholders, this doesn’t need to be an f-string:
- task.error = f"Command blocked: matches dangerous pattern" + task.error = "Command blocked: matches dangerous pattern"This also silences Ruff’s F541 warning.
82-97: Useget_running_loop()instead ofget_event_loop()in async contextInside an async function,
asyncio.get_running_loop()is the preferred API:- loop = asyncio.get_event_loop() + loop = asyncio.get_running_loop()This is more future-proof against changes in event-loop policy and matches current asyncio best practices.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
cortex/cli.py(8 hunks)cortex/install_parallel.py(1 hunks)tests/installer/__init__.py(1 hunks)tests/installer/test_parallel_install.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
tests/installer/test_parallel_install.py (1)
cortex/install_parallel.py (4)
run_parallel_install(131-253)ParallelTask(20-35)TaskStatus(11-16)duration(32-35)
cortex/install_parallel.py (1)
tests/installer/test_parallel_install.py (1)
log_callback(242-243)
cortex/cli.py (3)
cortex/validators.py (1)
validate_install_request(72-99)cortex/coordinator.py (2)
execute(252-299)InstallationCoordinator(65-350)cortex/install_parallel.py (1)
run_parallel_install(131-253)
🪛 GitHub Check: SonarCloud Code Analysis
tests/installer/test_parallel_install.py
[warning] 245-245: Replace the unused local variable "tasks" with "_".
cortex/install_parallel.py
[warning] 220-220: Remove this unnecessary list() call on an already iterable object.
[failure] 88-88: Use an async subprocess call in this async function instead of a synchronous one.
[failure] 38-38: Refactor this function to reduce its Cognitive Complexity from 19 to the 15 allowed.
[failure] 131-131: Refactor this function to reduce its Cognitive Complexity from 69 to the 15 allowed.
[warning] 38-38: Remove this "timeout" parameter and use a timeout context manager instead.
[warning] 193-193: Remove this unnecessary list() call on an already iterable object.
[warning] 135-135: Remove this "timeout" parameter and use a timeout context manager instead.
[warning] 76-76: Add replacement fields or use a normal string instead of an f-string.
cortex/cli.py
[failure] 115-115: Refactor this function to reduce its Cognitive Complexity from 103 to the 15 allowed.
[failure] 235-235: Define a constant instead of duplicating this literal "Installation failed" 4 times.
🪛 Ruff (0.14.8)
tests/installer/test_parallel_install.py
245-245: Unpacked variable tasks is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
cortex/install_parallel.py
76-76: f-string without any placeholders
Remove extraneous f prefix
(F541)
88-88: subprocess call with shell=True identified, security issue
(S602)
122-122: Do not catch blind exception: Exception
(BLE001)
157-157: Avoid specifying long messages outside the exception class
(TRY003)
cortex/cli.py
200-200: String contains ambiguous ℹ (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?
(RUF001)
252-252: Do not catch blind exception: Exception
(BLE001)
255-255: Use explicit conversion flag
Replace with conversion flag
(RUF010)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Agent
🔇 Additional comments (6)
tests/installer/__init__.py (1)
1-1: Package marker is fineSimple docstring-only
__init__cleanly declares the tests package; no issues here.tests/installer/test_parallel_install.py (1)
13-322: Parallel install tests give strong behavioral coverageThe suite exercises timing, dependency ordering (including diamond graphs), failure propagation, timeouts, empty inputs, per-task metadata, and log callbacks against the public
run_parallel_installAPI. This is a solid baseline for the new parallel executor.cortex/cli.py (2)
188-257: Parallel branch error handling and history updates look consistent with sequential pathThe new parallel execution branch mirrors the sequential flow by:
- Printing a clear success message and total duration on success.
- Updating
InstallationHistorywithSUCCESS/FAILEDand including an error message where available.- Emitting rollback/history hints for the user.
This keeps user-visible behavior and history records consistent between modes. The inline
parallel_log_callbackintegration withcx_printalso looks good.
115-176: Parallel install path lacks dependency tracking for sequenced operationsThe
installmethod callsrun_parallel_installwithout a dependency graph or ordering constraints. This risks incorrect execution order for multi-step installations where later steps depend on earlier ones completing first (e.g.,apt updatebeforeapt install, or service configuration before service start).Unless
CommandInterpreter.parsefilters commands to return only truly independent steps, the--parallelflag should either:
- Pass an explicit dependency graph via the
dependenciesparameter to preserve required ordering, or- Implement conservative defaults that only parallelize clearly safe groupings
Current behavior treats all commands as independent, which is unsafe for typical system installations.
cortex/install_parallel.py (2)
19-35: Task model and duration tracking are well structured
ParallelTaskcleanly encapsulates per-task metadata (status, output, timing), andduration()provides a simple derived metric for higher-level reporting. This structure aligns well with how the CLI and tests consume task data.
58-71: Dangerous-command patterns duplicated from sequential path
run_single_taskdefines its ownDANGEROUS_PATTERNSlist. The sequentialInstallationCoordinatoralready uses a globalDANGEROUS_PATTERNSset for exactly this purpose. Duplicating the patterns here risks the two paths drifting over time, so parallel installs might allow commands that sequential installs would block (or vice versa), weakening your safety guarantees.It would be better to centralize these patterns, for example by importing the existing constant or moving them to a shared module used by both coordinator and parallel executor.
There was a problem hiding this comment.
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 adds a parallel task execution system for Cortex installations, enabling concurrent execution of independent installation steps. The implementation introduces a new async-based parallel execution engine alongside the existing sequential coordinator, with CLI integration via a --parallel flag.
Key Changes
- New async parallel execution engine (
install_parallel.py) with dependency graph resolution, concurrent task execution (max 4 workers), and security validation matching the sequential coordinator - CLI integration adds
--parallelflag to the install command while maintaining backward compatibility with sequential execution as the default - Comprehensive test suite with 13 test cases covering parallel execution, dependency handling, failure scenarios, and edge cases
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 16 comments.
| File | Description |
|---|---|
cortex/install_parallel.py |
New parallel execution engine with async task scheduling, dependency resolution, security validation, and timeout handling |
cortex/cli.py |
Added --parallel flag support, integrated parallel execution path, cleaned up unused imports and improved None-checking in error handling |
tests/installer/test_parallel_install.py |
Comprehensive test suite covering parallel execution, dependency ordering, failure handling, timeouts, and integration scenarios |
tests/installer/__init__.py |
Package initialization file for installer tests |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (7)
cortex/validators.py (1)
12-26: Good consolidation of dangerous patterns; consider strengthening therm -rfpattern.Centralizing
DANGEROUS_PATTERNSin validators.py is a good approach for maintainability. However, therm -rfpattern at line 14 might miss some dangerous variants:
rm -rf /*(the pattern expects a space before/or*, but/*is a single token)rm -rf ~orrm -rf $HOMEConsider a more comprehensive pattern:
DANGEROUS_PATTERNS = [ - r'rm\s+-rf\s+[/\*]', + r'rm\s+-rf\s+(/|~|\*|\$)', r'rm\s+--no-preserve-root',Also consider adding
>>\s*/etc/for append redirects if that's a concern.tests/installer/test_parallel_install.py (1)
15-38: Consider using pytest-asyncio for cleaner async tests.The current pattern of wrapping async code in
asyncio.run()works, but usingpytest-asynciowith@pytest.mark.asynciodecorator would be more idiomatic and reduce boilerplate:import pytest @pytest.mark.asyncio async def test_parallel_runs_faster_than_sequential(self): """Verify that parallel execution is faster for independent tasks.""" commands = [...] success, tasks = await run_parallel_install(commands, timeout=10) # assertions...This would require adding
pytest-asyncioto dev dependencies.cortex/cli.py (2)
188-191: Move parallel execution imports to module level.The
asyncioandrun_parallel_installimports are done inline within the conditional block. While this works, it's generally better practice to have imports at the module level for clarity and to avoid repeated import overhead if the function is called multiple times.Add these imports at the top of the file with other imports:
import asyncio from cortex.install_parallel import run_parallel_installThen remove lines 190-191.
252-256: Consider catching more specific exceptions.The broad
Exceptioncatch is flagged by static analysis. While it's acceptable for a top-level error boundary, you could improve error reporting by catching more specific exceptions first.+ except asyncio.CancelledError: + if install_id: + history.update_installation(install_id, InstallationStatus.FAILED, "Operation cancelled") + self._print_error("Parallel execution cancelled") + return 130 except Exception as e: if install_id: history.update_installation(install_id, InstallationStatus.FAILED, str(e)) - self._print_error(f"Parallel execution failed: {str(e)}") + self._print_error(f"Parallel execution failed: {e!s}") return 1cortex/install_parallel.py (3)
103-117: Consider catchingsubprocess.TimeoutExpiredexplicitly.The
subprocess.run()call can raisesubprocess.TimeoutExpiredif the internal timeout fires before the asyncio timeout. While the genericExceptionhandler will catch it, explicit handling would provide clearer error messages consistent withcoordinator.py.except asyncio.TimeoutError: task.status = TaskStatus.FAILED task.error = f"Command timed out after {timeout} seconds" task.end_time = time.time() if log_callback: log_callback(f"Finished {task.name} (failed)", "error") return False + except subprocess.TimeoutExpired: + task.status = TaskStatus.FAILED + task.error = f"Command timed out after {timeout} seconds" + task.end_time = time.time() + if log_callback: + log_callback(f"Finished {task.name} (failed)", "error") + return False + except Exception as e:
176-176: Consider makingmax_workersconfigurable.The thread pool is hardcoded to 4 workers. For systems with more cores or when running many independent tasks, this could be a bottleneck. Consider exposing this as a parameter with a sensible default.
async def run_parallel_install( commands: List[str], descriptions: Optional[List[str]] = None, dependencies: Optional[Dict[int, List[int]]] = None, timeout: int = 300, stop_on_error: bool = True, - log_callback: Optional[Callable] = None + log_callback: Optional[Callable] = None, + max_workers: int = 4 ) -> tuple: ... - executor = concurrent.futures.ThreadPoolExecutor(max_workers=4) + executor = concurrent.futures.ThreadPoolExecutor(max_workers=max_workers)
120-141: Improve docstring return type annotation.The docstring states the return type as
tuplebut should be more specific to match best practices and aid IDE tooling. A previous review also flagged this.Returns: - tuple[bool, List[ParallelTask]]: Success status and list of all tasks + Tuple[bool, List[ParallelTask]]: (all_success, task_list) where all_success + is True if no tasks failed, and task_list contains all ParallelTask objects. """And update the return type hint:
-) -> tuple: +) -> Tuple[bool, List[ParallelTask]]:
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
.github/workflows/codeql.yml(0 hunks)cortex/cli.py(8 hunks)cortex/coordinator.py(1 hunks)cortex/install_parallel.py(1 hunks)cortex/validators.py(1 hunks)requirements.txt(1 hunks)tests/installer/test_parallel_install.py(1 hunks)
💤 Files with no reviewable changes (1)
- .github/workflows/codeql.yml
🧰 Additional context used
🧬 Code graph analysis (2)
tests/installer/test_parallel_install.py (3)
src/sandbox_executor.py (1)
success(52-54)cortex/logging_system.py (1)
error(219-221)cortex/coordinator.py (1)
duration(36-39)
cortex/install_parallel.py (6)
cortex/cli.py (1)
status(620-675)cortex/logging_system.py (1)
error(219-221)cortex/coordinator.py (1)
duration(36-39)tests/installer/test_parallel_install.py (1)
log_callback(237-238)src/sandbox_executor.py (2)
failed(57-59)success(52-54)src/progress_tracker.py (1)
cancel(464-500)
🪛 Ruff (0.14.8)
cortex/cli.py
200-200: String contains ambiguous ℹ (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?
(RUF001)
252-252: Do not catch blind exception: Exception
(BLE001)
255-255: Use explicit conversion flag
Replace with conversion flag
(RUF010)
cortex/install_parallel.py
77-77: subprocess call with shell=True identified, security issue
(S602)
111-111: Do not catch blind exception: Exception
(BLE001)
146-146: Avoid specifying long messages outside the exception class
(TRY003)
🔇 Additional comments (9)
cortex/coordinator.py (1)
12-14: LGTM!Clean refactor to import
DANGEROUS_PATTERNSfrom the shared validators module instead of defining it locally. This ensures consistent security validation across both sequential and parallel execution paths.tests/installer/test_parallel_install.py (1)
1-9: LGTM! Comprehensive test coverage for parallel execution.The test suite covers key scenarios including dependency ordering, failure propagation, timeout handling, and diamond dependency graphs. The use of
python -ccommands makes tests cross-platform compatible.cortex/cli.py (3)
213-219: Good fix for duration calculation.The duration calculation now properly handles
Nonevalues using generator expressions withdefault=Noneand explicitis not Nonechecks. This addresses the previous review feedback about incorrect handling whenend_timecould be 0 orNone.
892-898: Underscore prefix addresses unused variable warnings.The parser variables are now prefixed with
_to indicate they're intentionally unused. This is a common Python convention and addresses the static analysis warnings from previous reviews.
905-905: LGTM! --parallel flag properly integrated.The
--parallelflag is correctly added to the install subparser and properly passed through to theinstall()method.cortex/install_parallel.py (3)
10-10: Good use of shared DANGEROUS_PATTERNS.Importing
DANGEROUS_PATTERNSfrom the centralized validators module ensures consistent security validation and addresses the previous review feedback about code duplication.
69-86: Good timeout handling with dual timeout approach.The implementation correctly uses both
subprocess.run(..., timeout=timeout)for the process itself andasyncio.wait_for(..., timeout=timeout + 5)for the async wrapper. The comment aboutshell=Trueaddresses the previous review feedback. The 5-second buffer for asyncio overhead is reasonable.
194-205: Good deadlock/cycle detection implementation.This addresses the critical issue from previous reviews about potential infinite loops when tasks have unresolvable dependencies. The implementation correctly detects when no progress can be made and marks remaining tasks as skipped.
requirements.txt (1)
12-12: No action needed—PyYAML is already used in the codebase.PyYAML is imported and used in
src/config_manager.pyandcortex/user_preferences.py, making it a legitimate dependency. AddingPyYAML>=6.0.0to requirements.txt is appropriate even though it's not imported directly by the changed files in this PR.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
cortex/cli.py (5)
181-188:installmethod complexity grows; consider extracting helpersAdding the
parallel: boolflag and upfrontvalidate_install_requestcall is correct, butCortexCLI.installis now very large (as Sonar notes). Consider extracting helpers (e.g._run_install_sequential,_run_install_parallel,_record_install_success/failure) to reduce cognitive complexity and make future changes safer.
242-247: Sequential vs parallel execution share duplicated failure-handling logicThe sequential and parallel branches both construct error messages, update
InstallationHistory, and print very similar “Installation failed” output. This duplication is what Sonar is flagging and makes changes error-prone. Consider centralizing this into a small helper that takesinstall_idand an optionalerror_msg, updates history, and prints the common messaging.+ def _handle_install_failure(self, history, install_id, error_msg: str | None = None): + message = error_msg or "Installation failed" + if install_id: + history.update_installation(install_id, InstallationStatus.FAILED, message) + print(f"\n📝 Installation recorded (ID: {install_id})") + print(f" View details: cortex history show {install_id}") + self._print_error("Installation failed") + if error_msg: + print(f" Error: {error_msg}", file=sys.stderr)Then call
_handle_install_failure(...)from both the parallel and sequential failure paths.Also applies to: 324-366
545-546: Avoid unconditional tracebacks in CLI error pathPrinting a full traceback for
edit_preferrors can be noisy for users and may leak internal details. Since you already have a verbose mode, consider gating the traceback onself.verbose(or logging it instead).- except Exception as e: - self._print_error(f"Failed to edit preferences: {str(e)}") - traceback.print_exc() + except Exception as e: + self._print_error(f"Failed to edit preferences: {str(e)}") + if self.verbose: + traceback.print_exc()
576-601: Tighten Ollama/config/history status checks (unused var and f-string nits)The Ollama and config/history status additions are useful; a few small cleanups will also satisfy the static analysis hints:
- Drop the unused
respbinding fromurlopen.- Remove f-strings where no interpolation occurs.
- ollama_host = os.environ.get('OLLAMA_HOST', 'http://localhost:11434') - try: - req = urllib.request.Request(f"{ollama_host}/api/tags", method='GET') - with urllib.request.urlopen(req, timeout=2) as resp: - cx_print(f"Ollama: [bold]Running[/bold] ({ollama_host})", "success") - except Exception: - cx_print(f"Ollama: [bold]Not running[/bold]", "info") - cx_print(" Start: ollama serve", "info") + ollama_host = os.environ.get('OLLAMA_HOST', 'http://localhost:11434') + try: + req = urllib.request.Request(f"{ollama_host}/api/tags", method="GET") + with urllib.request.urlopen(req, timeout=2): + cx_print(f"Ollama: [bold]Running[/bold] ({ollama_host})", "success") + except Exception: + cx_print("Ollama: [bold]Not running[/bold]", "info") + cx_print(" Start: ollama serve", "info") @@ - config_path = os.path.expanduser('~/.cortex/config.json') + config_path = os.path.expanduser("~/.cortex/config.json") if os.path.exists(config_path): cx_print(f"Config: {config_path}", "info") else: - cx_print(f"Config: Not created yet", "info") + cx_print("Config: Not created yet", "info") @@ - history_path = os.path.expanduser('~/.cortex/history.db') + history_path = os.path.expanduser("~/.cortex/history.db") if os.path.exists(history_path): cx_print(f"History: {history_path}", "info") else: - cx_print(f"History: Not created yet", "info") + cx_print("History: Not created yet", "info")
680-681:--parallelflag wiring is correct; optional UX tweak with--executeThe CLI correctly plumbs
--parallelintoCortexCLI.install(..., parallel=args.parallel), and the flag only has effect when--executeis set (since the parallel/sequential branch is underif execute:). Behavior is safe; if you want to make it clearer to users, you could either mention in the help text that--parallelonly applies with--execute, or enforce that combination via argparse (e.g., documenting or validating ininstall).Also applies to: 737-737
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
cortex/cli.py(10 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cortex/cli.py (2)
cortex/coordinator.py (2)
execute(238-285)InstallationCoordinator(51-336)cortex/install_parallel.py (1)
run_parallel_install(120-269)
🪛 GitHub Check: SonarCloud Code Analysis
cortex/cli.py
[failure] 181-181: Refactor this function to reduce its Cognitive Complexity from 101 to the 15 allowed.
[failure] 301-301: Define a constant instead of duplicating this literal "Installation failed" 4 times.
[warning] 583-583: Add replacement fields or use a normal string instead of an f-string.
[warning] 580-580: Remove the unused local variable "resp".
[warning] 594-594: Add replacement fields or use a normal string instead of an f-string.
[warning] 600-600: Add replacement fields or use a normal string instead of an f-string.
🔇 Additional comments (3)
cortex/cli.py (3)
65-71: API key error handling now avoids blank error linesConditionally printing the validation error only when
erroris non-empty prevents empty “Error:” lines while preserving existing behavior. This looks good.
254-287: Parallel execution integration and duration calculation look correctThe
asyncio.run(run_parallel_install(...))integration, logging callback, and None-safe duration calculation viamax_end/min_startare coherent and handle the earlier edge cases (noend_time/start_time) without producing bogus durations. The branch correctly only usestotal_durationon success.
694-701: Preferences subcommands and parser wiring line up with implementationThe
check-prefandedit-prefsubparsers, including thevalidateaction, align with the methods implemented onCortexCLIand make those flows reachable from the CLI. Argument shapes look consistent with howcheck_prefandedit_prefuse them.




Related Issue
Closes #269
Summary
Implemented parallel task execution system for Cortex that enables concurrent execution of independent installation steps, providing 2-3x speedup for complex multi-step installations.
Key Features Implemented
1. Core Parallel Execution Engine (install_parallel.py)
2. CLI Integration (cli.py)
--parallelflag tocortex installcommandsubprocess,validate_installation_id,ValidationError)shutil,traceback,urllib.request)3. Comprehensive Test Suite (test_parallel_install.py)
test as user
Files Changed: 4 files -
Checklist
pytest tests/)[#XX] Description#video
https://drive.google.com/file/d/1GIzYu3dzfB0w2S_LU3lH7SgXsZAUCx2s/view?usp=sharing
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.