Skip to content

Commit 016c338

Browse files
Add support for --memory-max=n and --cpu-quota=n% [#113]
1 parent 99ab2e4 commit 016c338

File tree

1 file changed

+47
-5
lines changed

1 file changed

+47
-5
lines changed

bin/rsc

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
### --force Force an action
3232
### --full More of the same, e.g. output or file removal
3333
### --no-ssh Skip anything involving SSH
34-
###
3534
### --env-pattern=<re> Regular expression matching environment variables to be
3635
### exported. To export all, use "^.+$". To export none,
3736
### use "^$". (Default: "^.+$")
@@ -48,6 +47,9 @@
4847
### 'rsc' specifies the RSC configuration, 'rstudio' the
4948
### RStudio configuration, and 'sessions' on the RStudio
5049
### sessions storage
50+
### --cpu-quota=<quota> Limit CPU quota of R sessions (requires CGroups)
51+
### --memory-max=<size> Maximum memory use before R sessions are killed
52+
### (requires CGroups)
5153
### ---
5254
###
5355
### Example:
@@ -75,7 +77,7 @@
7577
### rsc reset --force
7678
### rsc reset --which=sessions
7779
###
78-
### Version: 0.17.0-9000
80+
### Version: 0.17.0-9001
7981
### Copyright: Henrik Bengtsson (2022-2024) and Harry Putnam (2022)
8082
### License: ISC
8183

@@ -1140,6 +1142,8 @@ function launch_rserver {
11401142
local workdir
11411143
local -i rs_pid
11421144
local port
1145+
local -a cmd
1146+
11431147
workdir=$(config_dir)
11441148
assert_dir_exists "${workdir}"
11451149

@@ -1150,14 +1154,36 @@ function launch_rserver {
11501154

11511155
port=$(rserver_port)
11521156
assert_port_free "${port}"
1157+
1158+
cmd=()
1159+
1160+
if [[ -n ${cpu_quota} ]] || [[ -n ${memory_max} ]]; then
1161+
mdebug "Launch RStudio Server with CGroups limits:"
1162+
mdebug "- cpu_quota=${cpu_quota}"
1163+
mdebug "- memory_max=${memory_max}"
1164+
if ! command -v systemd-run &> /dev/null; then
1165+
error "Cannot apply CPU and memory limits to the RStudio Server, because 'systemd-run' was not found"
1166+
fi
1167+
cmd=("systemd-run" "--user" "--scope")
1168+
if [[ -n ${cpu_quota} ]]; then
1169+
cmd+=("--property=CPUQuota=${cpu_quota}")
1170+
fi
1171+
if [[ -n ${memory_max} ]]; then
1172+
cmd+=("--property=MemoryMax=${memory_max}")
1173+
cmd+=("--property=MemorySwapMax=${memory_max}")
1174+
fi
1175+
mdebug "- Launcher: ${cmd[*]}"
1176+
fi
1177+
1178+
cmd+=("rserver" "--config-file=\"${workdir}/rserver.conf\"")
11531179

11541180
pid_file=$(rserver_pid_file)
1155-
mdebug "rserver --config-file=\"${workdir}/rserver.conf\" &"
1181+
mdebug "${cmd[*]} &"
11561182
if $dryrun; then
1157-
echo "DRYRUN: rserver --config-file=\"${workdir}/rserver.conf\""
1183+
echo "DRYRUN: ${cmd[*]}"
11581184
sleep 10 &
11591185
else
1160-
rserver --config-file="${workdir}/rserver.conf" &
1186+
eval "${cmd[*]}" &
11611187
fi
11621188
rs_pid=$!
11631189
echo "${rs_pid}" > "${pid_file}"
@@ -1502,6 +1528,8 @@ field=
15021528
auth=${RSC_AUTH:-auth-via-su}
15031529
revtunnel=()
15041530
ssh=${RSC_SSH:-true}
1531+
cpu_quota=${RSC_CPU_QUOTA}
1532+
memory_max=${RSC_MEMORY_MAX}
15051533

15061534
## Should 'rsession' inherit exported environment variables from the
15071535
## 'rsc' process? If 'false', then the default behavior of 'rserver'
@@ -1609,6 +1637,16 @@ while [[ $# -gt 0 ]]; do
16091637
elif [[ "${key}" == "revtunnel" ]]; then
16101638
[[ -z "${value}" ]] && error "Option '--revtunnel' must not be empty"
16111639
mapfile -t revtunnel < <(parse_revtunnel "${value}")
1640+
elif [[ "${key}" == "cpu-quota" ]]; then
1641+
cpu_quota=${value}
1642+
if ! grep -q -E "^[[:digit:]]+%$" <<< "${value}"; then
1643+
error "Unknown value for option --cpu-quota=${value}"
1644+
fi
1645+
elif [[ "${key}" == "memory-max" ]]; then
1646+
memory_max=${value}
1647+
if ! grep -q -E "^[[:digit:]]+(|K|M|G|T)$" <<< "${value}"; then
1648+
error "Unknown value for option --memory-max=${value}"
1649+
fi
16121650
else
16131651
error "Unknown option: $1"
16141652
fi
@@ -1676,6 +1714,8 @@ mdebug "auth: ${auth}"
16761714
mdebug "RSC_AUTH_ARG_2: ${RSC_AUTH_ARG_2}"
16771715
mdebug "revtunnel: [n=${#revtunnel[@]}] ${revtunnel[*]}"
16781716
mdebug "ssh: ${ssh}"
1717+
mdebug "cpu_quota=${cpu_quota}"
1718+
mdebug "memory_max=${memory_max}"
16791719
mdebug "RSC_AUTH: ${RSC_AUTH:-<not set>}"
16801720
mdebug "RSC_ENV_PATTERN: ${RSC_ENV_PATTERN:-<not set>}"
16811721
mdebug "RSC_LOCALPORT: ${RSC_LOCALPORT:-<not set>}"
@@ -1685,6 +1725,8 @@ mdebug "RSC_RSESSION_TIMEOUT: ${RSC_RSESSION_TIMEOUT:-<not set>}"
16851725
mdebug "RSC_SSH: ${RSC_SSH:-<not set>}"
16861726
mdebug "RSC_SSH_LOGIN_HOSTNAME: ${RSC_SSH_LOGIN_HOSTNAME:-<not set>}"
16871727
mdebug "RSC_SSH_TIMEOUT: ${RSC_SSH_TIMEOUT:-<not set>}"
1728+
mdebug "RSC_CPU_QUOTA: ${RSC_CPU_QUOTA:-<not set>}"
1729+
mdebug "RSC_MEMORY_MAX: ${RSC_MEMORY_MAX:-<not set>}"
16881730
mdebug "_RSC_RSERVER_HOSTNAME_: ${_RSC_RSERVER_HOSTNAME_:-<not set>}"
16891731
mdebug "_RSC_RSERVER_PORT_: ${_RSC_RSERVER_PORT_:-<not set>}"
16901732
mdebug "_RSC_RSERVER_PID_: ${_RSC_RSERVER_PID_:-<not set>}"

0 commit comments

Comments
 (0)