feat(task): minimal interactive tty scheduler barrier#8464
feat(task): minimal interactive tty scheduler barrier#8464
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a significant enhancement to the task scheduler by integrating an interactive TTY model. The core objective is to provide a robust mechanism for interactive tasks to run without interference from other concurrent processes, while also ensuring that injected sub-tasks correctly inherit and respect these interactive barriers. This change improves the reliability and predictability of task execution, particularly for user-facing interactive commands, and addresses potential deadlock scenarios in complex task dependencies. Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Pull request overview
This PR introduces a minimal “interactive TTY” execution model into the existing DAG task scheduler, primarily by enforcing a runtime-wide concurrency barrier for interactive tasks while preserving --jobs semantics and avoiding deadlocks in mixed runtime/injected task chains.
Changes:
- Add interactive barrier semantics to the scheduler via semaphore permit policies + deterministic permit acquisition ordering.
- Propagate internal env markers across injected subgraphs to prevent deadlocks and to preserve interactive barriers.
- Expose
interactiveacross JSON/task schemas and related CLI/MCP APIs; improve TTY/raw handling (restore termios, Ctrl-C interruption detection) and add e2e coverage.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/ui/ctrlc_stub.rs | Add was_interrupted() stub API for non-unix/tests. |
| src/ui/ctrlc.rs | Track sticky Ctrl-C interruption state for mise run. |
| src/task/task_scheduler.rs | Add permit ordering primitives + max permit tracking into scheduler context. |
| src/task/task_output_handler.rs | Align “runtime slot” detection; avoid panic for injected tasks in replacing output mode. |
| src/task/task_helpers.rs | Introduce runtime-slot helpers + injected-chain env markers for barrier/permit behavior. |
| src/task/task_executor.rs | Propagate barrier/permit markers to injected tasks; interactive TTY passthrough and stopping-on-Ctrl-C. |
| src/task/mod.rs | Add interactive task field + has_runtime_script() helper. |
| src/task/deps.rs | Make leaf scheduling deterministic by sorting ready leaves. |
| src/cmd.rs | Track raw-mode child PIDs; restore Unix terminal state after raw execution. |
| src/cli/tasks/ls.rs | Include interactive in JSON output. |
| src/cli/tasks/info.rs | Include interactive in JSON output. |
| src/cli/run.rs | Implement permit-count policy + ordered permit acquisition to support interactive barrier and deadlock avoidance. |
| src/cli/mcp.rs | Include interactive in MCP task payloads. |
| schema/mise.json | Add interactive to task schema variants. |
| schema/mise-task.json | Add interactive to task schema variants. |
| e2e/tasks/test_task_mixed_injected_respects_jobs1 | Add e2e regression coverage for mixed parent+injected behavior under --jobs=1. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Greptile SummaryThis PR introduces a minimal interactive TTY scheduler barrier into mise's existing DAG task scheduler. Interactive tasks ( Key findings:
Confidence Score: 4/5
Sequence DiagramsequenceDiagram
participant Sched as Scheduler Loop
participant SpawnJob as spawn_sched_job
participant AcqGuard as acquire_permit_guard
participant Semaphore as Semaphore (max_permits)
participant Executor as TaskExecutor
participant InjectWait as inject_and_wait
Sched->>SpawnJob: (interactive_task, deps)
SpawnJob->>SpawnJob: permit_count = max_permits<br/>permit_order = fetch_add(order_next)
SpawnJob->>SpawnJob: in_flight++
SpawnJob->>AcqGuard: acquire_permit_guard(permit_count, permit_order)
AcqGuard->>AcqGuard: wait until cursor == order
AcqGuard->>Semaphore: acquire_many_owned(max_permits) ← blocks all other tasks
Semaphore-->>AcqGuard: permit granted
AcqGuard->>AcqGuard: cursor++, notify_waiters()
AcqGuard-->>SpawnJob: (permit, should_run=true)
SpawnJob->>Executor: run_task_sched(interactive_task)
Executor->>Executor: ensure! stdin is_terminal()
Executor->>Executor: stdin/stdout/stderr = Stdio::inherit()
Executor->>InjectWait: inject_and_wait(injected_children,<br/>interactive_barrier=true, parent_holds_permit=false)
InjectWait->>InjectWait: add __MISE_INTERACTIVE_CHAIN=1 to env
InjectWait->>Sched: send injected child tasks (permit_count=0, bypass semaphore)
Sched-->>InjectWait: children complete
InjectWait-->>Executor: done
Executor-->>SpawnJob: Ok(())
SpawnJob->>Semaphore: drop permit (max_permits released)
SpawnJob->>SpawnJob: in_flight--
Note over Sched,Semaphore: Regular tasks queued after interactive task<br/>are blocked in ordering wait until permit released
Last reviewed commit: c49c340 |
There was a problem hiding this comment.
Code Review
This pull request introduces a minimal interactive TTY model into the existing DAG scheduler, significantly enhancing its capability to handle interactive tasks and complex task dependencies. The changes include a robust permit acquisition mechanism to prevent deadlocks, especially under --jobs=1 for mixed parent/injected child chains, and ensures proper TTY state restoration on Unix systems. The propagation of interactive barriers and parent permits to injected subtasks is well-implemented through environment variables, and the scheduler's responsiveness to Ctrl-C interruptions has been improved. The addition of a new e2e test for a specific concurrency scenario is a valuable contribution to the project's test suite.
9d720d0 to
ad2c456
Compare
|
Thanks for iterating on this. The PR is still more complex than it needs to be though. The semaphore-draining approach ( The goal is simple: only one interactive task runs at a time, and no other tasks run concurrently with it. This maps directly to a
Here's roughly what it should look like in // Add to SpawnContext:
pub interactive_lock: Arc<tokio::sync::RwLock<()>>,
// In spawn_sched_job, after permit acquisition:
let _interactive_guard = if task.interactive {
Some(ctx.interactive_lock.write_owned().await)
} else {
Some(ctx.interactive_lock.read_owned().await)
};That's it for the scheduler side. No ticket locks, no env var markers, no semaphore draining. The The parts of this PR that are fine and should be kept:
The parts that should be removed/replaced:
Could you simplify this down to the This comment was generated by Claude Code. |
ad2c456 to
5682d24
Compare
|
Thanks again for the review and discussion here. I opened a new PR that supersedes this one: #8473. I also want to clarify a misunderstanding on my side: I hadn’t understood that the intended RwLock scope was the finest task runtime segment (i.e. only around actual command execution), rather than the entire task lifecycle. The new PR follows that segment-level locking model. This new PR keeps the implementation intentionally minimal and avoids the extra ticket/env-marker/semaphore-drain complexity discussed here. |
Summary
This PR implements a minimal interactive TTY model in the existing DAG scheduler, with a small, runtime-focused diff.
What's changed
1) Interactive barrier in the scheduler (main change)
Interactive execution is enforced with semaphore policy in the existing scheduler:
max_permits) so no unrelated runtime task can run concurrently.__MISE_INTERACTIVE_CHAIN=1) and bypass permit acquisition, so they run under the parent barrier.__MISE_PARENT_PERMIT_CHAIN=1) to bypass permit acquisition.--jobsis respected).Other changes (small)
interactiveintasks info --json,tasks ls --json, MCPmise://tasks, and task schemas.--jobs=1.Validation
cargo fmt --allcargo check -qcargo build -q./e2e/run_test tasks/test_task_mixed_injected_respects_jobs1./e2e/run_test tasks/test_task_injected_runtime_jobs1_deadlock_regression./e2e/run_test tasks/test_task_interactive_mixed_external_barrier./e2e/run_test tasks/test_task_interactive_scheduler./e2e/run_test tasks/test_task_interactive_scheduler_extended./e2e/run_test tasks/test_task_interactive_pty_scheduler_matrix_slow./e2e/run_test tasks/test_task_info./e2e/run_test tasks/test_task_ls./e2e/run_test tasks/test_task_interactive_schema_api./e2e/run_test cli/test_mcp_tasks_interactive