Skip to content

Commit ac29e5a

Browse files
committed
fix: harden backend shutdown and dmg cleanup
1 parent 51b25a3 commit ac29e5a

2 files changed

Lines changed: 63 additions & 9 deletions

File tree

.github/workflows/build-desktop-tauri.yml

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -286,12 +286,15 @@ jobs:
286286
detach_sleep_seconds=2
287287
rw_dmg_image_prefix='/src-tauri/target/'
288288
rw_dmg_image_suffix_regex='/bundle/macos/rw\..*\.dmg$'
289+
# hdiutil temporary writable images often mount under /Volumes/dmg.*,
290+
# but macOS/tauri naming can vary; keep this pattern configurable.
291+
rw_dmg_mountpoint_regex="${ASTRBOT_DESKTOP_MACOS_RW_DMG_MOUNT_REGEX:-^/Volumes/(dmg\\.|rw\\.|dmg-|rw-)}"
289292
allow_global_helper_cleanup="${ASTRBOT_DESKTOP_MACOS_ALLOW_GLOBAL_HELPER_KILL:-0}"
290293
log_file=""
291294
workspace_root="${GITHUB_WORKSPACE:-$(pwd)}"
292-
workspace_root_raw="${workspace_root%/}"
293-
workspace_root="${workspace_root_raw}"
294295
workspace_root="${workspace_root%/}"
296+
declare -a canonical_path_cache_keys=()
297+
declare -a canonical_path_cache_values=()
295298
296299
cleanup_log_file() {
297300
if [ -n "${log_file:-}" ]; then
@@ -318,20 +321,39 @@ jobs:
318321
319322
canonicalize_path() {
320323
local raw_path="$1"
321-
python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "${raw_path}"
324+
local idx
325+
for idx in "${!canonical_path_cache_keys[@]}"; do
326+
if [ "${canonical_path_cache_keys[$idx]}" = "${raw_path}" ]; then
327+
printf '%s\n' "${canonical_path_cache_values[$idx]}"
328+
return 0
329+
fi
330+
done
331+
332+
local resolved_path
333+
if ! resolved_path="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "${raw_path}" 2>/dev/null)"; then
334+
resolved_path="${raw_path}"
335+
fi
336+
canonical_path_cache_keys+=("${raw_path}")
337+
canonical_path_cache_values+=("${resolved_path}")
338+
printf '%s\n' "${resolved_path}"
322339
}
323340
341+
workspace_root_canonical="$(canonicalize_path "${workspace_root}")"
342+
workspace_root_canonical="${workspace_root_canonical%/}"
343+
324344
is_workspace_rw_dmg_image() {
325345
local image="$1"
326346
local normalized_image
327347
normalized_image="$(canonicalize_path "${image}")"
328348
local candidate
329349
for candidate in "${image}" "${normalized_image}"; do
350+
candidate="${candidate%/}"
330351
if [[ "${candidate}" == "${workspace_root}${rw_dmg_image_prefix}"* ]] &&
331352
[[ "${candidate}" =~ ${rw_dmg_image_suffix_regex} ]]; then
332353
return 0
333354
fi
334-
if [[ "${candidate}" == "${workspace_root_raw}${rw_dmg_image_prefix}"* ]] &&
355+
if [[ -n "${workspace_root_canonical}" ]] &&
356+
[[ "${candidate}" == "${workspace_root_canonical}${rw_dmg_image_prefix}"* ]] &&
335357
[[ "${candidate}" =~ ${rw_dmg_image_suffix_regex} ]]; then
336358
return 0
337359
fi
@@ -386,7 +408,9 @@ jobs:
386408
387409
cleanup_stale_dmg_state() {
388410
local dmg_mounts
389-
dmg_mounts="$(mount | awk '$3 ~ /^\/Volumes\/dmg\./ { print $3 }' || true)"
411+
dmg_mounts="$(mount | awk -v mount_regex="${rw_dmg_mountpoint_regex}" '
412+
$1 ~ /^\/dev\/disk/ && $3 ~ mount_regex { print $3 }
413+
' || true)"
390414
if [ -n "${dmg_mounts}" ]; then
391415
while IFS= read -r mount_point; do
392416
[ -z "${mount_point}" ] && continue

src-tauri/src/main.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,24 +2383,54 @@ fn wait_for_child_exit(child: &mut Child, timeout: Duration) -> bool {
23832383
fn stop_child_process_gracefully(child: &mut Child, timeout: Duration) -> bool {
23842384
#[cfg(target_os = "windows")]
23852385
{
2386-
let _ = Command::new("taskkill")
2386+
let gentle_status = Command::new("taskkill")
23872387
.args(["/pid", &child.id().to_string(), "/t"])
23882388
.stdout(Stdio::null())
23892389
.stderr(Stdio::null())
23902390
.stdin(Stdio::null())
23912391
.status();
2392-
return wait_for_child_exit(child, timeout);
2392+
if !wait_for_child_exit(child, timeout) {
2393+
let force_status = Command::new("taskkill")
2394+
.args(["/pid", &child.id().to_string(), "/t", "/f"])
2395+
.stdout(Stdio::null())
2396+
.stderr(Stdio::null())
2397+
.stdin(Stdio::null())
2398+
.status();
2399+
append_desktop_log(&format!(
2400+
"backend graceful stop timed out, force-kill issued: pid={}, gentle={:?}, force={:?}",
2401+
child.id(),
2402+
gentle_status,
2403+
force_status
2404+
));
2405+
return wait_for_child_exit(child, Duration::from_millis(2200));
2406+
}
2407+
return true;
23932408
}
23942409

23952410
#[cfg(not(target_os = "windows"))]
23962411
{
2397-
let _ = Command::new("kill")
2412+
let term_status = Command::new("kill")
23982413
.args(["-TERM", &child.id().to_string()])
23992414
.stdout(Stdio::null())
24002415
.stderr(Stdio::null())
24012416
.stdin(Stdio::null())
24022417
.status();
2403-
wait_for_child_exit(child, timeout)
2418+
if !wait_for_child_exit(child, timeout) {
2419+
let kill_status = Command::new("kill")
2420+
.args(["-KILL", &child.id().to_string()])
2421+
.stdout(Stdio::null())
2422+
.stderr(Stdio::null())
2423+
.stdin(Stdio::null())
2424+
.status();
2425+
append_desktop_log(&format!(
2426+
"backend graceful stop timed out, force-kill issued: pid={}, term={:?}, kill={:?}",
2427+
child.id(),
2428+
term_status,
2429+
kill_status
2430+
));
2431+
return wait_for_child_exit(child, Duration::from_millis(1500));
2432+
}
2433+
true
24042434
}
24052435
}
24062436

0 commit comments

Comments
 (0)