mirror of
https://github.com/openai/codex.git
synced 2026-10-25 18:28:38 +00:00
Add an explicit app-server daemon update command (#43562)
## What changed Add `codex app-server daemon update` to check the latest stable release once, even when automatic updates are disabled. The command requires an installer-owned latest-channel standalone installation and reports `updated`, `noUpdate`, or `unsupported` as JSON, including installed and running versions. Route manual requests through the updater so scheduled and manual installs share one owner and accepted updates continue if the CLI exits. Restart a running managed daemon when its binary or version differs from the selected installation; this may interrupt active or queued work. Return installer failures as command errors and retry requests across updater replacement. ## Testing Add coverage for manual updates with automatic updates disabled, queued requests, same-version binary replacement, updater handoff retries, and unsupported installations or unmanaged servers. GitOrigin-RevId: 240b63c79bae3a64a80768131a30da70900a4d62
This commit is contained in:
@@ -787,6 +787,9 @@ enum AppServerDaemonSubcommand {
|
||||
/// Restart the local app server daemon.
|
||||
Restart,
|
||||
|
||||
/// Update the standalone installation and restart the managed daemon (may interrupt work).
|
||||
Update,
|
||||
|
||||
/// Enable remote control for future starts and a currently running managed daemon.
|
||||
EnableRemoteControl,
|
||||
|
||||
@@ -1378,6 +1381,10 @@ async fn cli_main(
|
||||
AppServerDaemonSubcommand::Restart => {
|
||||
print_app_server_daemon_output(AppServerLifecycleCommand::Restart).await?;
|
||||
}
|
||||
AppServerDaemonSubcommand::Update => {
|
||||
let output = codex_app_server_daemon::update().await?;
|
||||
println!("{}", serde_json::to_string(&output)?);
|
||||
}
|
||||
AppServerDaemonSubcommand::EnableRemoteControl => {
|
||||
print_app_server_remote_control_output(AppServerRemoteControlMode::Enabled)
|
||||
.await?;
|
||||
@@ -2616,6 +2623,7 @@ fn app_server_subcommand_name(subcommand: Option<&AppServerSubcommand>) -> &'sta
|
||||
AppServerDaemonSubcommand::Bootstrap(_) => "app-server daemon bootstrap",
|
||||
AppServerDaemonSubcommand::Start => "app-server daemon start",
|
||||
AppServerDaemonSubcommand::Restart => "app-server daemon restart",
|
||||
AppServerDaemonSubcommand::Update => "app-server daemon update",
|
||||
AppServerDaemonSubcommand::EnableRemoteControl => {
|
||||
"app-server daemon enable-remote-control"
|
||||
}
|
||||
|
||||
@@ -168,6 +168,18 @@ fn managed_start_keeps_updater_on_marker_mismatch_but_stops_it_for_pin() -> Resu
|
||||
std::fs::write(&marker, "0.1.0-other-target")?;
|
||||
assert_eq!(daemon.lifecycle("start")?["status"], "alreadyRunning");
|
||||
assert_eq!(daemon.pid("app-server-updater.pid")?, updater_pid);
|
||||
assert_eq!(daemon.lifecycle("update")?["status"], "unsupported");
|
||||
std::thread::sleep(Duration::from_millis(250));
|
||||
let updater_state = Command::new("/bin/ps")
|
||||
.args(["-p", &updater_pid.to_string(), "-o", "stat="])
|
||||
.output()?;
|
||||
ensure!(
|
||||
updater_state.status.success()
|
||||
&& !String::from_utf8_lossy(&updater_state.stdout)
|
||||
.trim()
|
||||
.starts_with('Z'),
|
||||
"updater exited during the latest marker transition"
|
||||
);
|
||||
|
||||
std::fs::remove_file(marker)?;
|
||||
|
||||
@@ -242,6 +254,7 @@ fn unmanaged_app_server_does_not_launch_updater() -> Result<()> {
|
||||
let output = daemon.lifecycle("start")?;
|
||||
assert_eq!(output["status"], "alreadyRunning");
|
||||
assert_eq!(output["backend"], Value::Null);
|
||||
assert_eq!(daemon.lifecycle("update")?["status"], "unsupported");
|
||||
assert!(
|
||||
!daemon
|
||||
.home
|
||||
@@ -251,3 +264,19 @@ fn unmanaged_app_server_does_not_launch_updater() -> Result<()> {
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manual_update_rejects_an_unowned_installation() -> Result<()> {
|
||||
let daemon = TestDaemon::new()?;
|
||||
std::fs::remove_file(
|
||||
daemon
|
||||
.home
|
||||
.path()
|
||||
.join("packages/standalone/auto-update-version"),
|
||||
)?;
|
||||
|
||||
assert_eq!(daemon.lifecycle("update")?["status"], "unsupported");
|
||||
assert!(daemon.pid("app-server.pid").is_err());
|
||||
assert!(daemon.pid("app-server-updater.pid").is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user