Skip to content

Commit

Permalink
Adjust WEB_CONCURRENCY for memory heavy instances (#1196)
Browse files Browse the repository at this point in the history
* Update concurrency calculations for larger memory footprints

* Use 2048 MB WEB_MEMORY for memory heavy dynos

* Drop duplicate line from WEB_CONCURRENCY

* Adjust tests for memory heavy WEB_CONCURRENCY

* Adjust web concurrency test value

* Add changelog entry for web concurrency changes

* Fix typo in changelog
  • Loading branch information
joshwlewis authored Jan 24, 2024
1 parent 10fd15b commit 88df97e
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 30 deletions.
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

0 comments on commit 88df97e

Please sign in to comment.