diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d937645b..b731d1649 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/profile/WEB_CONCURRENCY.sh b/profile/WEB_CONCURRENCY.sh index 95e769101..9e7d7eddf 100755 --- a/profile/WEB_CONCURRENCY.sh +++ b/profile/WEB_CONCURRENCY.sh @@ -4,7 +4,7 @@ calculate_concurrency() { local available=$1 local web_memory=$2 - echo $(($available/$web_memory)) + echo $(( available / web_memory )) } validate_concurrency() { @@ -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" @@ -41,9 +40,8 @@ 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 @@ -51,9 +49,19 @@ bound_memory() { 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 @@ -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 diff --git a/test/unit b/test/unit index e822401bb..4afdd44ed 100755 --- a/test/unit +++ b/test/unit @@ -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 @@ -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))"