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

feat: fallback to loading when encountering proxy timeout #1511

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/guides/nginx-startup.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ kb_sync_latest_only

# Building and Running NGINX Docker Image

- [Building and Running NGINX Docker Image](#building-and-running-nginx-docker-image)
- [Building](#building)
- [Configuration](#configuration)
- [HTTPS or SSL](#https-or-ssl)
- [Basic Auth](#basic-auth)
- [Multi-Site](#multi-site)
- [Ignore Parameters During Caching](#ignore-parameters-during-caching)
- [Access ICM Sitemap](#access-icm-sitemap)
- [Override Identity Providers by Path](#override-identity-providers-by-path)
- [Other](#other)
- [Features](#features)
- [Cache](#cache)
- [Loading Fallback](#loading-fallback)
- [Further References](#further-references)

We provide a Docker image based on [nginx](https://nginx.org/) for the [PWA deployment](../concepts/pwa-building-blocks.md#pwa---nginx).

## Building
Expand Down Expand Up @@ -163,6 +178,21 @@ If the cache feature is switched off, all caching for pre-rendered pages is disa
The cache duration for pre-rendered pages can be customized using `CACHE_DURATION_NGINX_OK` (for successful responses) and `CACHE_DURATION_NGINX_NF` (for 404 responses).
The value supplied must be in the `time` format that is supported by [nginx proxy_cache_valid](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_valid).

### Loading Fallback

When encountering high loads on the SSR container, the nginx container can be configured to serve a loading page after a certain timeout.
This way the user will get a fast response that can be completed by the browser using the ICM REST API.
Meanwhile the nginx container will cache the page in the background after it finishes rendering.The fully rendered page will be served on the next request.

Requests from Crawlers will bypass this mechanism and will be served directly from the SSR container with potentially longer response durations.

To activate this feature, set the environment variable `LOADING_FALLBACK` to `"on"`.
The timeout can be configured using the environment variable `LOADING_FALLBACK_TIMEOUT` using a time format (i.e. `40s`, `15m`, ...).

> :warning: It is not recommended to use this feature by default, as it will not solve the underlying issue.
> In most cases the SSR container should be scaled out dynamically to handle intermittent high loads.
> It might also be worth investigating default render times and do some code optimizations to get faster SSR responses.

## Further References

- [Concept - Multi-Site Handling](../concepts/multi-site-handling.md)
Expand Down
5 changes: 4 additions & 1 deletion nginx/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
FROM nginx:1.22
RUN apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y apache2-utils libnss3-tools
COPY nginx.conf /etc/nginx/nginx.conf
COPY *.conf /etc/nginx/
COPY loading-fallback.sh.tmpl /loading-fallback.sh.tmpl
COPY features /etc/nginx/features/
COPY templates /etc/nginx/templates/
COPY docker-entrypoint.d/*.sh /docker-entrypoint.d/
Expand All @@ -21,5 +22,7 @@ ENV CACHE_DURATION_NGINX_OK=10m
ENV CACHE_DURATION_NGINX_NF=60m
ENV LOGFORMAT=main
ENV LOG_ALL=on
ENV LOADING_FALLBACK=off
ENV LOADING_FALLBACK_TIMEOUT=10s

EXPOSE 80 443 9113
11 changes: 11 additions & 0 deletions nginx/bot-map.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# https://stackoverflow.com/a/24820722
map $http_user_agent $is_bot {
default 0;
~*(google|bing|yandex|msnbot) 1;
~*(AltaVista|Googlebot|Slurp|BlackWidow|Bot|ChinaClaw|Custo|DISCo|Download|Demon|eCatch|EirGrabber|EmailSiphon|EmailWolf|SuperHTTP|Surfbot|WebWhacker) 1;
~*(Express|WebPictures|ExtractorPro|EyeNetIE|FlashGet|GetRight|GetWeb!|Go!Zilla|Go-Ahead-Got-It|GrabNet|Grafula|HMView|Go!Zilla|Go-Ahead-Got-It) 1;
~*(rafula|HMView|HTTrack|Stripper|Sucker|Indy|InterGET|Ninja|JetCar|Spider|larbin|LeechFTP|Downloader|tool|Navroad|NearSite|NetAnts|tAkeOut|WWWOFFLE) 1;
~*(GrabNet|NetSpider|Vampire|NetZIP|Octopus|Offline|PageGrabber|Foto|pavuk|pcBrowser|RealDownload|ReGet|SiteSnagger|SmartDownload|SuperBot|WebSpider) 1;
~*(Teleport|VoidEYE|Collector|WebAuto|WebCopier|WebFetch|WebGo|WebLeacher|WebReaper|WebSauger|eXtractor|Quester|WebStripper|WebZIP|Wget|Widow|Zeus) 1;
~*(Twengabot|htmlparser|libwww|Python|perl|urllib|scan|Curl|email|PycURL|Pyth|PyQ|WebCollector|WebCopy|webcraw) 1;
}
3 changes: 3 additions & 0 deletions nginx/docker-entrypoint.d/40-gomplate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ then
fi

/gomplate -d "domains=$MULTI_CHANNEL_SOURCE" -d "overrideIdentityProviders=$OVERRIDE_IDENTITY_PROVIDERS_SOURCE" -d "cachingIgnoreParams=$CACHING_IGNORE_PARAMS_SOURCE" -d 'ipwhitelist=env:///BASIC_AUTH_IP_WHITELIST?type=application/yaml' --input-dir="/etc/nginx/templates" --output-map='/etc/nginx/conf.d/{{ .in | strings.ReplaceAll ".conf.tmpl" ".conf" }}'

/gomplate -d "domains=$MULTI_CHANNEL_SOURCE" -f /loading-fallback.sh.tmpl -o /loading-fallback.sh
chmod +x /loading-fallback.sh
5 changes: 5 additions & 0 deletions nginx/docker-entrypoint.d/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ if env | grep -iqE "^PROMETHEUS=(on|1|true|yes)$"
then
(sleep 5 && /nginx-prometheus-exporter)&
fi

if env | grep -iqE "^LOADING_FALLBACK=(on|1|true|yes)$"
then
(sleep 5 && /loading-fallback.sh)&
fi
12 changes: 3 additions & 9 deletions nginx/features/ssr-off.conf
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
# https://stackoverflow.com/a/24820722
map $http_user_agent $render_ssr {
default 0;
~*(google|bing|yandex|msnbot) 1;
~*(AltaVista|Googlebot|Slurp|BlackWidow|Bot|ChinaClaw|Custo|DISCo|Download|Demon|eCatch|EirGrabber|EmailSiphon|EmailWolf|SuperHTTP|Surfbot|WebWhacker) 1;
~*(Express|WebPictures|ExtractorPro|EyeNetIE|FlashGet|GetRight|GetWeb!|Go!Zilla|Go-Ahead-Got-It|GrabNet|Grafula|HMView|Go!Zilla|Go-Ahead-Got-It) 1;
~*(rafula|HMView|HTTrack|Stripper|Sucker|Indy|InterGET|Ninja|JetCar|Spider|larbin|LeechFTP|Downloader|tool|Navroad|NearSite|NetAnts|tAkeOut|WWWOFFLE) 1;
~*(GrabNet|NetSpider|Vampire|NetZIP|Octopus|Offline|PageGrabber|Foto|pavuk|pcBrowser|RealDownload|ReGet|SiteSnagger|SmartDownload|SuperBot|WebSpider) 1;
~*(Teleport|VoidEYE|Collector|WebAuto|WebCopier|WebFetch|WebGo|WebLeacher|WebReaper|WebSauger|eXtractor|Quester|WebStripper|WebZIP|Wget|Widow|Zeus) 1;
~*(Twengabot|htmlparser|libwww|Python|perl|urllib|scan|Curl|email|PycURL|Pyth|PyQ|WebCollector|WebCopy|webcraw) 1;
map $is_bot $render_ssr {
1 1;
0 0;
}

map $render_ssr $ssr_rewrite {
Expand Down
27 changes: 27 additions & 0 deletions nginx/loading-fallback.sh.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{{- define "clean-domain" -}}
{{ . | strings.ReplaceAll ".+" "_" | strings.ReplaceAll ".*" "_" }}
{{- end -}}
#!/bin/sh

mkdir -p /tmp/loading

fetch() {
target="/tmp/loading/$1/$2.html"
mkdir -p "$(dirname "$target")"
curl -s -o "$target" -H "Host: $1" "http://localhost:8080$2"
}

while true
do
{{- range $domain, $mapping := (ds "domains") }}
{{- $cdomain := tmpl.Exec "clean-domain" $domain -}}
{{- if $mapping | test.IsKind "map" }}
fetch "{{ $cdomain }}" "/loading"
{{- else }}
{{- range $mapping }}
fetch "{{ $cdomain }}" "{{ .baseHref }}/loading"
{{- end }}
{{- end }}
{{- end }}
sleep 300
done
3 changes: 3 additions & 0 deletions nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ http {

keepalive_timeout 65;

include /etc/nginx/bot-map.conf;

include /etc/nginx/conf.d/features.conf;

include /etc/nginx/conf.d/multi-channel.conf;
include /etc/nginx/conf.d/loading-fallback.conf;
}
53 changes: 53 additions & 0 deletions nginx/templates/loading-fallback.conf.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{{- define "clean-domain" -}}
{{ . | strings.ReplaceAll ".+" "_" | strings.ReplaceAll ".*" "_" }}
{{- end -}}

{{ if getenv "LOADING_FALLBACK" | strings.ToLower | regexp.Match "on|1|true|yes" }}
upstream real_server {
server localhost:8080 fail_timeout=0;
keepalive 15;
}

{{- range $domain, $mapping := (ds "domains") }}
server {
listen 80;
server_name ~^{{ $domain }}$;
proxy_set_header Host $http_host;
proxy_cache_bypass true;

# https://mailman.nginx.org/pipermail/nginx/2007-May/001031.html
if ($is_bot) {
rewrite ^(.*)$ /bot-bypass$1;
}
location /bot-bypass {
rewrite ^/bot-bypass(.*)$ $1 break;
proxy_pass http://real_server;
}

{{ if (has $mapping "channel") }}
location / {
proxy_pass http://real_server;
proxy_read_timeout {{ getenv "LOADING_FALLBACK_TIMEOUT" }};
error_page 504 =200 /loading.html;
}
location = /loading.html {
root /tmp/loading/{{ tmpl.Exec "clean-domain" $domain }};
}
{{- else -}}
{{ range $mapping }}
location {{ .baseHref }} {
proxy_pass http://real_server;
proxy_read_timeout {{ getenv "LOADING_FALLBACK_TIMEOUT" }};
error_page 504 =200 {{ .baseHref }}/loading.html;
}
location = {{ .baseHref }}/loading.html {
root /tmp/loading/{{ tmpl.Exec "clean-domain" $domain }};
}
{{ end }}
location / {
proxy_pass http://real_server;
}
{{ end }}
{{ end }}
}
{{ end }}
6 changes: 6 additions & 0 deletions nginx/templates/multi-channel.conf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@

rewrite '^(.*)$' '$1$default_rewrite_params' break;

{{ if getenv "LOADING_FALLBACK" | strings.ToLower | regexp.Match "on|1|true|yes" }}
proxy_ignore_client_abort on;
{{ end }}

proxy_pass {{ getenv "UPSTREAM_PWA" }};
proxy_buffer_size 128k;
proxy_buffers 4 256k;
Expand Down Expand Up @@ -91,6 +95,8 @@ server {

# https://ma.ttias.be/force-redirect-http-https-custom-port-nginx/
error_page 497 https://$http_host$request_uri;
{{ else if getenv "LOADING_FALLBACK" | strings.ToLower | regexp.Match "on|1|true|yes" }}
listen 8080;
{{ else }}
listen 80;
{{- end }}
Expand Down
Loading