-
Notifications
You must be signed in to change notification settings - Fork 25
176 lines (148 loc) · 5.5 KB
/
Copy pathservice-recovery.yml
File metadata and controls
176 lines (148 loc) · 5.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
name: Service Recovery
on:
workflow_dispatch:
pull_request:
paths:
- "Cargo.toml"
- "Cargo.lock"
- "src/**"
- "tests/**"
- "resources/**"
- ".github/workflows/service-integration.yml"
- ".github/workflows/service-recovery.yml"
push:
branches:
- "**"
paths:
- "Cargo.toml"
- "Cargo.lock"
- "src/**"
- "tests/**"
- "resources/**"
- ".github/workflows/service-integration.yml"
- ".github/workflows/service-recovery.yml"
permissions:
contents: read
jobs:
recovery:
name: Verify service recovery (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- name: Build service binaries
run: cargo build --release --features "standalone client"
- name: Install service (Unix)
if: runner.os != 'Windows'
run: sudo target/release/clash-verge-service-install --debug
- name: Kill service and verify recovery (Linux)
if: runner.os == 'Linux'
run: |
set -euo pipefail
service="clash-verge-service.service"
target/release/service-integration-driver ping
old_pid="$(systemctl show "$service" --property=MainPID --value)"
if [ -z "$old_pid" ] || [ "$old_pid" = "0" ]; then
sudo systemctl status "$service" --no-pager
exit 1
fi
sudo kill -9 "$old_pid"
for _ in {1..40}; do
sleep 1
new_pid="$(systemctl show "$service" --property=MainPID --value)"
active_state="$(systemctl show "$service" --property=ActiveState --value)"
if [ "$active_state" = "active" ] && [ -n "$new_pid" ] && [ "$new_pid" != "0" ] && [ "$new_pid" != "$old_pid" ]; then
target/release/service-integration-driver ping
echo "Recovered service PID $old_pid -> $new_pid"
exit 0
fi
done
sudo systemctl status "$service" --no-pager
exit 1
- name: Kill service and verify recovery (macOS)
if: runner.os == 'macOS'
run: |
set -euo pipefail
service_id="io.github.clash-verge-rev.clash-verge-rev.service"
target/release/service-integration-driver ping
get_pid() {
sudo launchctl print "system/$service_id" 2>/dev/null | awk -F'= ' '/^[[:space:]]*pid = / { print $2; exit }' || true
}
old_pid="$(get_pid)"
if [ -z "$old_pid" ] || [ "$old_pid" = "-" ]; then
sudo launchctl print "system/$service_id"
exit 1
fi
sudo kill -9 "$old_pid"
for _ in {1..40}; do
sleep 1
new_pid="$(get_pid)"
if [ -n "$new_pid" ] && [ "$new_pid" != "-" ] && [ "$new_pid" != "$old_pid" ]; then
target/release/service-integration-driver ping
echo "Recovered service PID $old_pid -> $new_pid"
exit 0
fi
done
sudo launchctl print "system/$service_id"
exit 1
- name: Install service (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
& "$env:GITHUB_WORKSPACE\target\release\clash-verge-service-install.exe"
Start-Sleep -Seconds 2
- name: Kill service and verify recovery (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$serviceName = "clash_verge_service"
$driver = "$env:GITHUB_WORKSPACE\target\release\service-integration-driver.exe"
& $driver ping
if ($LASTEXITCODE -ne 0) {
throw "IPC was not reachable before killing the service process"
}
$service = Get-CimInstance Win32_Service -Filter "Name='$serviceName'"
$oldPid = [int]$service.ProcessId
if ($oldPid -le 0) {
throw "Service is not running"
}
Stop-Process -Id $oldPid -Force
$deadline = (Get-Date).AddSeconds(60)
while ((Get-Date) -lt $deadline) {
Start-Sleep -Seconds 1
$service = Get-CimInstance Win32_Service -Filter "Name='$serviceName'"
$newPid = [int]$service.ProcessId
if ($service.State -eq "Running" -and $newPid -gt 0 -and $newPid -ne $oldPid) {
& $driver ping
if ($LASTEXITCODE -ne 0) {
throw "IPC did not respond after service restart"
}
Write-Host "Recovered service PID $oldPid -> $newPid"
exit 0
}
}
sc.exe queryex $serviceName
throw "Service did not restart after forced process exit"
- name: Uninstall service (Unix)
if: always() && runner.os != 'Windows'
run: |
if [ -x target/release/clash-verge-service-uninstall ]; then
sudo target/release/clash-verge-service-uninstall --debug
fi
- name: Uninstall service (Windows)
if: always() && runner.os == 'Windows'
shell: pwsh
run: |
$service = Get-Service -Name "clash_verge_service" -ErrorAction SilentlyContinue
if ($null -ne $service) {
& "$env:GITHUB_WORKSPACE\target\release\clash-verge-service-uninstall.exe"
}