Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust WEB_CONCURRENCY for memory heavy instances #1196

Merged
merged 9 commits into from
Jan 24, 2024
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## main

- Adjust WEB_CONCURRENCY calculations to support larger, memory heavy instances. ([#1196](https://github.com/heroku/heroku-buildpack-nodejs/pull/1196))
- Added Node.js version 21.6.1.

## v234 (2024-01-16)

- Added Node.js version 21.6.0.
Expand Down
51 changes: 26 additions & 25 deletions profile/WEB_CONCURRENCY.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ calculate_concurrency() {
local available=$1
local web_memory=$2

echo $(($available/$web_memory))
echo $(( available / web_memory ))
}

validate_concurrency() {
Expand All @@ -13,11 +13,10 @@ validate_concurrency() {

if (( concurrency < 1 )); then
concurrency=1
ret=1
elif (( concurrency > 200 )); then
# Ex: This will happen on Dokku on DO
concurrency=1
ret=2
ret=1
fi

echo "$concurrency"
Expand All @@ -41,19 +40,28 @@ detect_memory() {

bound_memory() {
local detected=$1
local max_detected_memory=14336

# The hardcoded value is 16GB of memory
# Memory is bound to the maximum memory of known dyno types: ~126 GB
local max_detected_memory=129024
if (( detected > max_detected_memory )); then
echo "$max_detected_memory"
else
echo "$detected"
fi
}

warn_high_web_concurrency() {
default_web_memory() {
local available_memory=$1
# Allow more memory per process on memory heavy dyno types.
if (( available_memory > 16384 )); then
echo 2048
else
echo 512
fi
}

warn_web_concurrency() {
echo "Could not determine a reasonable value for WEB_CONCURRENCY.
This is likely due to running the Heroku NodeJS buildpack on a non-Heroku
This is likely due to running the Heroku Node.js buildpack on a non-Heroku
platform.

WEB_CONCURRENCY has been set to ${1}. Please review whether this value is
Expand All @@ -62,24 +70,17 @@ appropriate for your application.
}

DETECTED=$(detect_memory 512)
export MEMORY_AVAILABLE=${MEMORY_AVAILABLE-$(bound_memory $DETECTED)}
export WEB_MEMORY=${WEB_MEMORY-512}
WEB_CONCURRENCY=${WEB_CONCURRENCY-$(calculate_concurrency "$MEMORY_AVAILABLE" "$WEB_MEMORY")}
validated_concurrency=$(validate_concurrency "$WEB_CONCURRENCY")
case $? in # validate_concurrency exit code indicates result
1)
# too low
export WEB_CONCURRENCY=$validated_concurrency
;;
2)
# too high
warn_high_web_concurrency "$validated_concurrency" "$WEB_CONCURRENCY"
export MEMORY_AVAILABLE=${MEMORY_AVAILABLE-$(bound_memory "$DETECTED")}
export WEB_MEMORY=${WEB_MEMORY-$(default_web_memory "$MEMORY_AVAILABLE")}

# Calculate/validate WEB_CONCURRENCY if not already set
if [ -z "${WEB_CONCURRENCY}" ]; then
calculated_concurrency=$(calculate_concurrency "$MEMORY_AVAILABLE" "$WEB_MEMORY")
if ! validated_concurrency=$(validate_concurrency "$calculated_concurrency"); then
warn_web_concurrency "$validated_concurrency"
fi
export WEB_CONCURRENCY=$validated_concurrency
;;
0)
export WEB_CONCURRENCY
;;
esac
fi

if [[ "${LOG_CONCURRENCY+isset}" && "$LOG_CONCURRENCY" == "true" ]]; then
log_concurrency
Expand Down
12 changes: 7 additions & 5 deletions test/unit
Original file line number Diff line number Diff line change
Expand Up @@ -315,12 +315,12 @@ testWebConcurrencyProfileScript() {
# memory in MB of a Peformance-L dyno
assertEquals "14336" "$(bound_memory 14336)"

# one more MB
assertEquals "14336" "$(bound_memory 14337)"

# On non-Heroku systems `detect_memory` can return non-sensically large values
# In this case, we should bound
assertEquals "14336" "$(bound_memory 1000000)"
# so bound to largest known dyno size
assertEquals "129024" "$(bound_memory 129024)"

# One larger than largest known
assertEquals "129024" "$(bound_memory 129025)"

# test calculate_concurrency

Expand All @@ -332,6 +332,8 @@ testWebConcurrencyProfileScript() {
assertEquals "5" "$(calculate_concurrency 2560 512)"
# Performance-L
assertEquals "28" "$(calculate_concurrency 14336 512)"
# Memory heavy
assertEquals "31" "$(calculate_concurrency 63488 2048)"

# In case some very large memory available value gets passed in
assertEquals "1" "$(validate_concurrency $(calculate_concurrency 103401 512))"
Expand Down