diff --git a/Dockerfile b/Dockerfile index 998d7afc13..acd38db0d8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -71,6 +71,8 @@ COPY ./deploy/docker/templates/nginx/* \ ./deploy/docker/templates/docker.env.sh \ ./deploy/docker/templates/mockdb_postgres.sql \ ./deploy/docker/templates/users_postgres.sql \ + ./deploy/docker/templates/appsmith_starting.html \ + ./deploy/docker/templates/appsmith_initializing.html \ templates/ # Add bootstrapfile diff --git a/deploy/docker/entrypoint.sh b/deploy/docker/entrypoint.sh index defcc43015..b5f768b668 100755 --- a/deploy/docker/entrypoint.sh +++ b/deploy/docker/entrypoint.sh @@ -271,6 +271,9 @@ configure_supervisord() { fi cp -f "$SUPERVISORD_CONF_PATH/application_process/"*.conf /etc/supervisor/conf.d + + # Copy Supervisor Listiner confs to conf.d + cp -f "$SUPERVISORD_CONF_PATH/event_listeners/"*.conf /etc/supervisor/conf.d # Disable services based on configuration if [[ -z "${DYNO}" ]]; then @@ -377,7 +380,20 @@ runEmbeddedPostgres=1 init_postgres || runEmbeddedPostgres=0 } +init_loading_pages(){ + local starting_page="/opt/appsmith/templates/appsmith_starting.html" + local initializing_page="/opt/appsmith/templates/appsmith_initializing.html" + local editor_load_page="/opt/appsmith/editor/loading.html" + # Update default nginx page for initializing page + cp "$initializing_page" /var/www/html/index.nginx-debian.html + # Start nginx page to display the Appsmith is Initializing page + nginx + # Update editor nginx page for starting page + cp "$starting_page" "$editor_load_page" +} + # Main Section +init_loading_pages init_env_file setup_proxy_variables unset_unused_variables @@ -413,7 +429,10 @@ fi mkdir -p /appsmith-stacks/data/{backup,restore} # Create sub-directory to store services log in the container mounting folder -mkdir -p /appsmith-stacks/logs/{backend,cron,editor,rts,mongodb,redis,postgres} +mkdir -p /appsmith-stacks/logs/{backend,cron,editor,rts,mongodb,redis,postgres,appsmithctl} + +# Stop nginx gracefully +nginx -s quit # Handle CMD command exec "$@" diff --git a/deploy/docker/scripts/supervisor_event_listener.py b/deploy/docker/scripts/supervisor_event_listener.py new file mode 100644 index 0000000000..5b659dddc1 --- /dev/null +++ b/deploy/docker/scripts/supervisor_event_listener.py @@ -0,0 +1,74 @@ +import os +import requests +import sys +import shutil +import time + +LOADING_TEMPLATE_PAGE = r'/opt/appsmith/templates/appsmith_starting.html' +LOADING_PAGE_EDITOR = r'/opt/appsmith/editor/loading.html' +BACKEND_HEALTH_ENDPOINT = "http://localhost/api/v1/health" + +def write_stdout(s): + # only eventlistener protocol messages may be sent to stdout + sys.stdout.write(s) + sys.stdout.flush() + +def write_stderr(s): + sys.stderr.write(s) + sys.stderr.flush() + +def wait_until_backend_healthy(): + sleep_sec = 3 + timeout_sec = 120 + for _ in range(timeout_sec//sleep_sec): + if requests.get(BACKEND_HEALTH_ENDPOINT).ok: + write_stderr('\nBackend is healthy\n') + break + time.sleep(sleep_sec) + + else: + write_stderr('\nBackend health check timed out\n') + + remove_loading_page() + +def remove_loading_page(): + if os.path.exists(LOADING_PAGE_EDITOR): + os.remove(LOADING_PAGE_EDITOR) + +def main(): + while True: + # transition from ACKNOWLEDGED to READY + write_stdout('READY\n') + + # read header line and print it to stderr + line = sys.stdin.readline() + write_stderr(line) + + # read event payload and print it to stderr + headers = dict(x.split(':', 1) for x in line.split()) + data = sys.stdin.read(int(headers['len'])) + + if 'PROCESS_STATE_STARTING' in line: + data_params = dict([ x.split(':') for x in data.split()]) + if data_params['groupname'] == 'backend': + write_stderr('\nBackend State: STARTING\n') + shutil.copyfile(LOADING_TEMPLATE_PAGE, LOADING_PAGE_EDITOR) + + elif 'PROCESS_STATE_RUNNING' in line: + data_params = dict([ x.split(':') for x in data.split()]) + if data_params['groupname'] == 'backend': + write_stderr('\nBackend State: RUNNING\n') + wait_until_backend_healthy() + write_stderr(data) + + elif 'PROCESS_STATE_FATAL' in line: + data_params = dict([ x.split(':') for x in data.split()]) + if data_params['groupname'] == 'backend': + write_stderr('\nBackend State: FATAL\n') + remove_loading_page() + + # transition from READY to ACKNOWLEDGED + write_stdout('RESULT 2\nOK') + +if __name__ == '__main__': + main() diff --git a/deploy/docker/templates/appsmith_initializing.html b/deploy/docker/templates/appsmith_initializing.html new file mode 100644 index 0000000000..fba1f0dab2 --- /dev/null +++ b/deploy/docker/templates/appsmith_initializing.html @@ -0,0 +1,87 @@ + + + + + + + Appsmith + + +
+

+ Please wait +

+

Appsmith is initializing. This might take a few minutes.

+
+
+ + + + diff --git a/deploy/docker/templates/appsmith_starting.html b/deploy/docker/templates/appsmith_starting.html new file mode 100644 index 0000000000..007a0dfce2 --- /dev/null +++ b/deploy/docker/templates/appsmith_starting.html @@ -0,0 +1,87 @@ + + + + + + + Appsmith + + +
+

+ Appsmith is starting. +

+

Please wait until Appsmith is ready. This process usually takes a minute.

+
+
+ + + + diff --git a/deploy/docker/templates/nginx/nginx-app-http.conf.template.sh b/deploy/docker/templates/nginx/nginx-app-http.conf.template.sh index 44ba7c763d..8311fd337e 100644 --- a/deploy/docker/templates/nginx/nginx-app-http.conf.template.sh +++ b/deploy/docker/templates/nginx/nginx-app-http.conf.template.sh @@ -70,7 +70,7 @@ server { proxy_set_header X-Forwarded-Host \$origin_host; location / { - try_files \$uri /index.html =404; + try_files /loading.html \$uri /index.html =404; } location ~ ^/static/(js|css|media)\b { diff --git a/deploy/docker/templates/nginx/nginx-app-https.conf.template.sh b/deploy/docker/templates/nginx/nginx-app-https.conf.template.sh index 875ac373fc..94c9e995de 100644 --- a/deploy/docker/templates/nginx/nginx-app-https.conf.template.sh +++ b/deploy/docker/templates/nginx/nginx-app-https.conf.template.sh @@ -87,7 +87,7 @@ server { } location / { - try_files \$uri /index.html =404; + try_files /loading.html \$uri /index.html =404; } location ~ ^/static/(js|css|media)\b { diff --git a/deploy/docker/templates/supervisord/application_process/backend.conf b/deploy/docker/templates/supervisord/application_process/backend.conf index 0c99eeb166..64ecaca2aa 100644 --- a/deploy/docker/templates/supervisord/application_process/backend.conf +++ b/deploy/docker/templates/supervisord/application_process/backend.conf @@ -4,7 +4,7 @@ command=/opt/appsmith/run-with-env.sh /opt/appsmith/run-java.sh priority=20 autostart=true autorestart=true -startsecs=10 +startsecs=20 startretries=3 stdout_logfile=/appsmith-stacks/logs/%(program_name)s/%(program_name)s-%(ENV_HOSTNAME)s.log redirect_stderr=true diff --git a/deploy/docker/templates/supervisord/event_listeners/eventlistener.conf b/deploy/docker/templates/supervisord/event_listeners/eventlistener.conf new file mode 100644 index 0000000000..4b9be55ee8 --- /dev/null +++ b/deploy/docker/templates/supervisord/event_listeners/eventlistener.conf @@ -0,0 +1,5 @@ +[eventlistener:event_listener] +command=python3 /opt/appsmith/supervisor_event_listener.py +events=PROCESS_STATE +stderr_logfile=/appsmith-stacks/logs/appsmithctl/eventlistener.log +priority=1 \ No newline at end of file