3scale / APIcast

3scale API Gateway
Apache License 2.0
304 stars 171 forks source link

Immediate, infinite recursion when configuration loader is set to `boot` and reloading is disabled #1467

Closed coderbydesign closed 3 weeks ago

coderbydesign commented 1 month ago

With the fix in #1399, it appears there was a regression introduced when using the following configuration, which is a use case where you'd want to load the configuration at boot, and never reload:

# load configuration at boot
APICAST_CONFIGURATION_LOADER: boot

# disable configuration refresh
APICAST_CONFIGURATION_CACHE:  -1

Prior to the fix for the above bug, the only way the configuration_loader executed the schedule method was if interval > 0 then, which would then refresh the configuration at whatever positive interval was defined in APICAST_CONFIGURATION_CACHE.

The changes introduced here make it so that even when you have refresh disabled via a negative number as documented here, this logic will always call the schedule method, and ultimately ngx.timer.at with a delay of -1 because the schedule method is recursive and uses the ttl, which will cause the timer to expire immediately (the same as a 0 value delay which is not an edge-case seen in APIcast since that's not valid with boot configuration) executing the callback immediately, and infinitely reloading the configuration.

This ultimately causes CPU and other resource consumption issues, and when done remotely has network and request implications trying to fetch the config.

Version
nginx version: openresty/1.21.4.3
quay.io/3scale/apicast-ci:openresty-1.21.4-1: 2024-04-29T20:39:47.030811444+10:00
Steps To Reproduce
  1. make development
  2. make dependencies
  3. Ensure this config [1] exists at /opt/app-root/src/config.json
  4. Run APICAST_LOG_LEVEL=info APICAST_WORKERS=1 THREESCALE_PORTAL_ENDPOINT=http://echo:8081/config/ THREESCALE_CONFIG_FILE=/opt/app-root/src/config.json APICAST_CONFIGURATION_LOADER=boot APICAST_CONFIGURATION_CACHE=-1 THREESCALE_DEPLOYMENT_ENV=staging APICAST_SERVICES_LIST=1234 ./bin/apicast
Current Result

You'll see that after the initial boot configuration loads, it then enters into the scheduler, and immediately and infinitely starts refreshing the configuration. Here is a sample of the output: https://gist.github.com/coderbydesign/f3d95680b27a34795c58e9906e784d71

Expected Result

We see the environment config loaded once at boot, with no schedule set for reloading configuration: https://gist.github.com/coderbydesign/0421cd55635007f3f45361eb6c35ee48

Additional Information

Thanks to @dagbay-rh for finding the initial root cause of our issue and helping here!

coderbydesign commented 1 month ago

Proposed PR in https://github.com/3scale/APIcast/pull/1468

tkan145 commented 1 month ago

@coderbydesign Thanks for your issue, make sense what you're reporting. Let me have a look, and I'll come back to you in the next couple of days.