Skip to content

Fix job unfreeze giving false negative when trying to unfreeze after killing the most recent job#16909

Open
peachey2k2 wants to merge 2 commits intonushell:mainfrom
peachey2k2:main
Open

Fix job unfreeze giving false negative when trying to unfreeze after killing the most recent job#16909
peachey2k2 wants to merge 2 commits intonushell:mainfrom
peachey2k2:main

Conversation

@peachey2k2
Copy link
Copy Markdown

Changes

  • Updated FrozenJob to store the timestamp of the last freeze.
  • Refactored remove_job() to replace the last job ID with the most recently unfrozen job, instead of blindly erasing it.

Fixes #16561

@peachey2k2 peachey2k2 force-pushed the main branch 2 times, most recently from 64b19c5 to 0d6ccb1 Compare October 21, 2025 14:35
@sholderbach sholderbach added the A:job-control The system to manage background jobs and concurrent tasks label Oct 21, 2025
Copy link
Copy Markdown
Member

@sholderbach sholderbach left a comment

Choose a reason for hiding this comment

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

Thanks for looking into this. I am gonna ping @cosineblast if he has special remarks as our resident job expert :)

Comment thread crates/nu-protocol/src/engine/jobs.rs Outdated
pub struct FrozenJob {
pub unfreeze: UnfreezeHandle,
pub tag: Option<String>,
pub timestamp: DateTime<Utc>,
Copy link
Copy Markdown
Member

@sholderbach sholderbach Oct 21, 2025

Choose a reason for hiding this comment

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

I am not sure if using chrono::DateTime is the best choice here. I don't think it has the monotonicity guarantees of std::time::Instant which should preserve the order of jobs even if you are messing with timezone or clock settings while a job is frozen.

If we don't need to directly present it to users having the support for timezones etc. would be overkill.

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.

Fair enough. My initial thought was to also show it to the users too, but figured that'd bloat the PR.

@peachey2k2 peachey2k2 force-pushed the main branch 2 times, most recently from 2d8e730 to 0b533b0 Compare October 21, 2025 16:28
@cosineblast
Copy link
Copy Markdown
Contributor

cosineblast commented Oct 24, 2025

Looks good to me!
I'd personally go for storing the order of jobs internally (e.g in a BTreeMap with a counter), but storing Instants in frozenjobs works very well, and it's much less overkill.
I just think it's worth having tests for this bugfix tho.

@peachey2k2
Copy link
Copy Markdown
Author

Sorry for the insane amount of amends, I should have been more careful.

I'm not very familiar with BTreeMap, but I'm guessing that'd mean faster reorders at the cost of more memory and doing more allocations. Either way, I doubt it'd make a difference, as almost no one will have enough jobs for it to matter.

@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented Dec 4, 2025

waiting for tests

@fdncred fdncred marked this pull request as draft December 4, 2025 17:23
@peachey2k2
Copy link
Copy Markdown
Author

peachey2k2 commented Dec 7, 2025

I've been looking into adding in the tests, but there's a problem. Let me explain:

#[test]
fn job_unfreeze_works() {
    let actual = nu!(r#"
        nu -c "kill -s 19 $nu.pid; echo meep"
        job unfreeze
    "#);

    assert!(actual.out.ends_with("meep"));
    assert_eq!(actual.err, "");
}

This is one of the tests I've written. 19 corresponds to SIGSTOP, which does the same thing as Ctrl+Z. In theory this should work, but it instead hangs and leaves the spawned nushell instance as a zombie process. But when I try the same lines on my terminal, it works perfectly:

$ nu -c "kill -s 19 $nu.pid; echo meep"; job unfreeze

Job 1 is frozen
meep

Of course, nu!() macro uses --commands to send in the commands. Adding another -c resulted in this:

$ nu -c 'nu -c "kill -s 19 $nu.pid; echo meep"; job unfreeze'
Error: nu::shell::io::uncategorized_error

  × I/O error
  ╰─▶   × Failed to unfreeze foreground process

   ╭────
 1 │ crates/nu-command/src/experimental/job_unfreeze.rs:148:21
   · ────────────────────────────┬────────────────────────────
   ·                             ╰── Uncategorized error
   ╰────

Error: nu::shell::non_zero_exit_code

  × External command had a non-zero exit code
   ╭─[entry #4:1:1]
 1 │ nu -c 'nu -c "kill -s 19 $nu.pid; echo meep"; job unfreeze'
   · ─┬
   ·  ╰── exited with code 1
   ╰────

The issue is that -c leads the shell to not be interactive. But the function setting the group ID for the main process exits early on non-interactive shells. And yes -i fixes this, but there are issues with that too.

I don't really know what the right approach would be in this case.

Edit: I used sh instead since that seems to work.

@peachey2k2 peachey2k2 marked this pull request as ready for review December 15, 2025 14:30
@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented Mar 17, 2026

@peachey2k2 can we get these conflicts resolved and move forward?

@peachey2k2
Copy link
Copy Markdown
Author

Sorry for not checking formatting. Also I commented out the tests so beware of that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A:job-control The system to manage background jobs and concurrent tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

job unfreeze gives false negative when trying to unfreeze after killing the most recent job

4 participants