feat: Display loading message in browser when Appsmith is starting (#22215)

## Description
Added Appsmith Initializing and Starting pages to inform the users that
Appsmith is starting up and they will need to wait for a few minutes
before their Appsmith deployment is up and running, instead of
displaying the 503 error like it earlier.


## Type of change
- New feature (non-breaking change which adds functionality)

# Media
Initialization page

![image](https://user-images.githubusercontent.com/20785806/230869925-a342e327-c714-4cfa-8283-cf6f5bd225b5.png)

Starting page

![image](https://user-images.githubusercontent.com/20785806/230869770-67654c0a-e4de-4d18-83dd-9f68230648e9.png)

[Demo
Video](https://drive.google.com/file/d/1sjvfbtbWHRqVfg0Vvf2JM6W3y61-KrWm/view?usp=share_link)
## How Has This Been Tested?
- Manual

---------

Co-authored-by: Shrikant Sharat Kandula <shrikant@appsmith.com>
Co-authored-by: Arpit Mohan <mohanarpit@users.noreply.github.com>
This commit is contained in:
Sumesh Pradhan 2023-04-19 18:20:59 +05:30 committed by GitHub
parent 2729bbff28
commit f1bf7b17dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 278 additions and 4 deletions

View File

@ -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

View File

@ -272,6 +272,9 @@ configure_supervisord() {
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
if [[ $isUriLocal -eq 0 ]]; 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 "$@"

View File

@ -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()

View File

@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" http-equiv="refresh" content="5"/>
<link
rel="shortcut icon"
href="https://assets.appsmith.com/appsmith-favicon-orange.ico"
/>
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<title>Appsmith</title>
</head>
<body>
<div class="main">
<p class="bold-text">
Please wait
</p>
<p>Appsmith is initializing. This might take a few minutes.</p>
<div class="loader"></div>
</div>
<style>
body,
html {
height: 100%;
overflow-x: hidden;
width: 100%;
background-color: #fff;
margin: 0;
color: #182026;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Open Sans, Helvetica Neue, Icons16, sans-serif;
font-size: 14px;
font-weight: 400;
letter-spacing: 0;
}
.main {
display: flex;
align-items: center;
height: 90%;
flex-direction: column;
margin-top: 5%;
text-align: center;
}
.bold-text {
font-family: system-ui;
font-weight: 700;
font-size: 24px;
margin: 24px 0 0;
}
.body-text {
margin: 8px 0 0;
}
/* Safari */
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.loader {
border: 4px solid #f3f3f3;
border-radius: 50%;
border-top: 4px solid #939090;
width: 30px;
height: 30px;
-webkit-animation: spin 1s linear infinite; /* Safari */
animation: spin 1s linear infinite;
}
</style>
</body>
</html>

View File

@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" http-equiv="refresh" content="3"/>
<link
rel="shortcut icon"
href="https://assets.appsmith.com/appsmith-favicon-orange.ico"
/>
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<title>Appsmith</title>
</head>
<body>
<div class="main">
<p class="bold-text">
Appsmith is starting.
</p>
<p>Please wait until Appsmith is ready. This process usually takes a minute. </p>
<div class="loader"></div>
</div>
<style>
body,
html {
height: 100%;
overflow-x: hidden;
width: 100%;
background-color: #fff;
margin: 0;
color: #182026;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Open Sans, Helvetica Neue, Icons16, sans-serif;
font-size: 14px;
font-weight: 400;
letter-spacing: 0;
}
.main {
display: flex;
align-items: center;
height: 90%;
flex-direction: column;
margin-top: 5%;
text-align: center;
}
.bold-text {
font-family: system-ui;
font-weight: 700;
font-size: 24px;
margin: 24px 0 0;
}
.body-text {
margin: 8px 0 0;
}
/* Safari */
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.loader {
border: 4px solid #f3f3f3;
border-radius: 50%;
border-top: 4px solid #939090;
width: 30px;
height: 30px;
-webkit-animation: spin 1s linear infinite; /* Safari */
animation: spin 1s linear infinite;
}
</style>
</body>
</html>

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -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