31
31
# ## --force Force an action
32
32
# ## --full More of the same, e.g. output or file removal
33
33
# ## --no-ssh Skip anything involving SSH
34
- # ##
35
34
# ## --env-pattern=<re> Regular expression matching environment variables to be
36
35
# ## exported. To export all, use "^.+$". To export none,
37
36
# ## use "^$". (Default: "^.+$")
48
47
# ## 'rsc' specifies the RSC configuration, 'rstudio' the
49
48
# ## RStudio configuration, and 'sessions' on the RStudio
50
49
# ## 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)
51
53
# ## ---
52
54
# ##
53
55
# ## Example:
75
77
# ## rsc reset --force
76
78
# ## rsc reset --which=sessions
77
79
# ##
78
- # ## Version: 0.17.0-9000
80
+ # ## Version: 0.17.0-9001
79
81
# ## Copyright: Henrik Bengtsson (2022-2024) and Harry Putnam (2022)
80
82
# ## License: ISC
81
83
@@ -1140,6 +1142,8 @@ function launch_rserver {
1140
1142
local workdir
1141
1143
local -i rs_pid
1142
1144
local port
1145
+ local -a cmd
1146
+
1143
1147
workdir=$( config_dir)
1144
1148
assert_dir_exists " ${workdir} "
1145
1149
@@ -1150,14 +1154,36 @@ function launch_rserver {
1150
1154
1151
1155
port=$( rserver_port)
1152
1156
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\" " )
1153
1179
1154
1180
pid_file=$( rserver_pid_file)
1155
- mdebug " rserver --config-file= \" ${workdir} /rserver.conf \" &"
1181
+ mdebug " ${cmd[*]} &"
1156
1182
if $dryrun ; then
1157
- echo " DRYRUN: rserver --config-file= \" ${workdir} /rserver.conf \" "
1183
+ echo " DRYRUN: ${cmd[*]} "
1158
1184
sleep 10 &
1159
1185
else
1160
- rserver --config-file= " ${workdir} /rserver.conf " &
1186
+ eval " ${cmd[*]} " &
1161
1187
fi
1162
1188
rs_pid=$!
1163
1189
echo " ${rs_pid} " > " ${pid_file} "
@@ -1502,6 +1528,8 @@ field=
1502
1528
auth=${RSC_AUTH:- auth-via-su}
1503
1529
revtunnel=()
1504
1530
ssh=${RSC_SSH:- true}
1531
+ cpu_quota=${RSC_CPU_QUOTA}
1532
+ memory_max=${RSC_MEMORY_MAX}
1505
1533
1506
1534
# # Should 'rsession' inherit exported environment variables from the
1507
1535
# # 'rsc' process? If 'false', then the default behavior of 'rserver'
@@ -1609,6 +1637,16 @@ while [[ $# -gt 0 ]]; do
1609
1637
elif [[ " ${key} " == " revtunnel" ]]; then
1610
1638
[[ -z " ${value} " ]] && error " Option '--revtunnel' must not be empty"
1611
1639
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
1612
1650
else
1613
1651
error " Unknown option: $1 "
1614
1652
fi
@@ -1676,6 +1714,8 @@ mdebug "auth: ${auth}"
1676
1714
mdebug " RSC_AUTH_ARG_2: ${RSC_AUTH_ARG_2} "
1677
1715
mdebug " revtunnel: [n=${# revtunnel[@]} ] ${revtunnel[*]} "
1678
1716
mdebug " ssh: ${ssh} "
1717
+ mdebug " cpu_quota=${cpu_quota} "
1718
+ mdebug " memory_max=${memory_max} "
1679
1719
mdebug " RSC_AUTH: ${RSC_AUTH:- <not set>} "
1680
1720
mdebug " RSC_ENV_PATTERN: ${RSC_ENV_PATTERN:- <not set>} "
1681
1721
mdebug " RSC_LOCALPORT: ${RSC_LOCALPORT:- <not set>} "
@@ -1685,6 +1725,8 @@ mdebug "RSC_RSESSION_TIMEOUT: ${RSC_RSESSION_TIMEOUT:-<not set>}"
1685
1725
mdebug " RSC_SSH: ${RSC_SSH:- <not set>} "
1686
1726
mdebug " RSC_SSH_LOGIN_HOSTNAME: ${RSC_SSH_LOGIN_HOSTNAME:- <not set>} "
1687
1727
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>} "
1688
1730
mdebug " _RSC_RSERVER_HOSTNAME_: ${_RSC_RSERVER_HOSTNAME_:- <not set>} "
1689
1731
mdebug " _RSC_RSERVER_PORT_: ${_RSC_RSERVER_PORT_:- <not set>} "
1690
1732
mdebug " _RSC_RSERVER_PID_: ${_RSC_RSERVER_PID_:- <not set>} "
0 commit comments