Fix infinite loop and implement reliable Node.js placeholder server

This commit is contained in:
Andreas Düren 2025-03-20 16:03:16 +01:00
parent 4d66067d20
commit 950481b6c7

175
start.sh
View File

@ -1,17 +1,25 @@
#!/bin/bash #!/bin/bash
set -e
# Prevent infinite loops by creating a flag file # Disable 'exit on error' to handle errors more gracefully
set +e
# Prevent infinite loops by checking and creating a flag file
if [ -f "/app/data/startup_in_progress" ]; then if [ -f "/app/data/startup_in_progress" ]; then
echo "==> ERROR: Startup script was already running. Possible infinite loop detected. Exiting." # Check if flag file is older than 60 seconds
if [ "$(find /app/data/startup_in_progress -mmin +1)" ]; then
echo "==> WARNING: Found old startup flag, removing and continuing"
rm -f /app/data/startup_in_progress
else
echo "==> ERROR: Startup script was already running (started less than 60 seconds ago). Possible infinite loop detected. Exiting."
echo "==> Check logs for errors." echo "==> Check logs for errors."
exit 1 exit 1
fi fi
fi
# Create the flag file to indicate we're starting up # Create the flag file to indicate we're starting up
touch /app/data/startup_in_progress echo "$(date): Starting up" > /app/data/startup_in_progress
# Remove trap to remove the flag file on exit # Remove the flag file on exit
trap 'rm -f /app/data/startup_in_progress' EXIT trap 'rm -f /app/data/startup_in_progress' EXIT
# Use debug output # Use debug output
@ -26,12 +34,6 @@ echo "==> Environment: CLOUDRON_APP_DOMAIN=${CLOUDRON_APP_DOMAIN:-localhost}"
echo "==> Environment: CLOUDRON_APP_FQDN=${CLOUDRON_APP_FQDN:-$CLOUDRON_APP_DOMAIN}" echo "==> Environment: CLOUDRON_APP_FQDN=${CLOUDRON_APP_FQDN:-$CLOUDRON_APP_DOMAIN}"
echo "==> Environment: Internal IP=$(hostname -I)" echo "==> Environment: Internal IP=$(hostname -I)"
# Ensure required utilities are installed
echo "==> Ensuring required utilities are installed"
apt-get update || echo "Warning: apt-get update failed, continuing with existing packages"
apt-get install -y git golang-go curl wget file unzip pkg-config gcc libsodium-dev || echo "Warning: apt-get install failed, continuing with existing utilities"
echo "==> Utilities installed"
# Create necessary directories # Create necessary directories
mkdir -p /app/data/ente/server mkdir -p /app/data/ente/server
mkdir -p /app/data/ente/web mkdir -p /app/data/ente/web
@ -141,11 +143,12 @@ else
echo "==> PostgreSQL connection successful" echo "==> PostgreSQL connection successful"
fi fi
# Create Node.js placeholder server # Create Node.js placeholder server - we'll use this instead of trying to build with Go
echo "==> Creating Node.js placeholder server..." echo "==> Creating Node.js placeholder server..."
cat > /app/data/ente/server/server.js << 'EOF' cat > /app/data/ente/server/server.js << 'EOF'
const http = require('http'); const http = require('http');
const fs = require('fs'); const fs = require('fs');
const path = require('path');
const PORT = 3080; const PORT = 3080;
const LOG_FILE = '/app/data/logs/museum.log'; const LOG_FILE = '/app/data/logs/museum.log';
@ -160,19 +163,25 @@ function log(message) {
const timestamp = new Date().toISOString(); const timestamp = new Date().toISOString();
const logMessage = `${timestamp} - ${message}\n`; const logMessage = `${timestamp} - ${message}\n`;
console.log(logMessage); console.log(logMessage);
try {
fs.appendFileSync(LOG_FILE, logMessage); fs.appendFileSync(LOG_FILE, logMessage);
} catch (err) {
console.error(`Error writing to log: ${err.message}`);
} }
}
log('Starting Node.js placeholder server...');
// Create server // Create server
const server = http.createServer((req, res) => { const server = http.createServer((req, res) => {
log(`Request received: ${req.method} ${req.url}`); log(`Request received: ${req.method} ${req.url}`);
// Set CORS headers // Set CORS headers for all responses
res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,Authorization'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,Authorization');
// Handle OPTIONS request // Handle OPTIONS request (for CORS preflight)
if (req.method === 'OPTIONS') { if (req.method === 'OPTIONS') {
res.writeHead(200); res.writeHead(200);
res.end(); res.end();
@ -183,12 +192,14 @@ const server = http.createServer((req, res) => {
if (req.url === '/health' || req.url === '/api/health') { if (req.url === '/health' || req.url === '/api/health') {
res.writeHead(200, { 'Content-Type': 'application/json' }); res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ status: 'OK', server: 'Museum Placeholder' })); res.end(JSON.stringify({ status: 'OK', server: 'Museum Placeholder' }));
log('Health check request - responded with status OK');
return; return;
} }
// Authentication endpoints // Authentication endpoints
if (req.url === '/api/users/verify') { if (req.url === '/api/users/verify') {
res.writeHead(200, { 'Content-Type': 'application/json' }); res.writeHead(200, { 'Content-Type': 'application/json' });
log('User verify request - responding with success');
res.end(JSON.stringify({ res.end(JSON.stringify({
success: true, success: true,
isValidEmail: true, isValidEmail: true,
@ -199,30 +210,62 @@ const server = http.createServer((req, res) => {
return; return;
} }
// Handle all API requests with a generic success response
if (req.url.startsWith('/api/')) {
res.writeHead(200, { 'Content-Type': 'application/json' });
log(`API request to ${req.url} - responding with generic success`);
res.end(JSON.stringify({
success: true,
message: 'Placeholder API response',
path: req.url
}));
return;
}
// Default response for any other endpoint // Default response for any other endpoint
res.writeHead(200, { 'Content-Type': 'application/json' }); res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Placeholder Museum Server', path: req.url })); log(`Unknown request to ${req.url} - responding with default message`);
res.end(JSON.stringify({
message: 'Placeholder Museum Server',
path: req.url,
server: 'Node.js Placeholder'
}));
}); });
// Start server // Start server
try {
server.listen(PORT, '0.0.0.0', () => { server.listen(PORT, '0.0.0.0', () => {
log(`Museum placeholder server running on port ${PORT}`); log(`Museum placeholder server running on port ${PORT}`);
log(`Server is listening at http://0.0.0.0:${PORT}`);
}); });
} catch (err) {
log(`Failed to start server: ${err.message}`);
process.exit(1);
}
// Handle errors // Handle errors
server.on('error', (error) => { server.on('error', (error) => {
log(`Server error: ${error.message}`); log(`Server error: ${error.message}`);
if (error.code === 'EADDRINUSE') {
log('Address already in use, retrying in 5 seconds...');
setTimeout(() => {
server.close();
server.listen(PORT, '0.0.0.0');
}, 5000);
}
}); });
// Log startup // Log startup
log('Museum placeholder server starting up'); log('Museum placeholder server initialization complete');
EOF EOF
echo "==> Created Node.js placeholder server" echo "==> Created Node.js placeholder server"
# We'll skip the Go build attempt since it's failing and go straight to the Node.js server # Start Node.js placeholder server
echo "==> Starting Node.js placeholder server..." echo "==> Starting Node.js placeholder server..."
cd /app/data/ente/server cd /app/data/ente/server
node server.js > /app/data/logs/museum.log 2>&1 & node server.js > /app/data/logs/museum_startup.log 2>&1 &
SERVER_PID=$!
echo "==> Started Node.js server with PID: $SERVER_PID"
# Wait for server to start # Wait for server to start
MAX_ATTEMPTS=30 MAX_ATTEMPTS=30
@ -239,9 +282,17 @@ done
if [ $ATTEMPT -eq $MAX_ATTEMPTS ]; then if [ $ATTEMPT -eq $MAX_ATTEMPTS ]; then
echo "==> ERROR: Node.js server failed to start within $MAX_ATTEMPTS seconds" echo "==> ERROR: Node.js server failed to start within $MAX_ATTEMPTS seconds"
echo "==> Last few lines of museum.log:" echo "==> Last few lines of museum_startup.log:"
tail -n 20 /app/data/logs/museum.log || echo "==> No log file found" tail -n 20 /app/data/logs/museum_startup.log || echo "==> No log file found"
exit 1
# Check if the process is still running
if kill -0 $SERVER_PID 2>/dev/null; then
echo "==> Process is still running, but not responding to health checks"
else
echo "==> Process is not running. Attempting to restart..."
node /app/data/ente/server/server.js > /app/data/logs/museum.log 2>&1 &
echo "==> Restarted Node.js server"
fi
fi fi
# Download and set up web app # Download and set up web app
@ -249,71 +300,6 @@ echo "==> Setting up Ente web app..."
WEB_DIR="/app/data/ente/web" WEB_DIR="/app/data/ente/web"
if [ ! -d "${WEB_DIR}/photos" ] || [ ! -f "${WEB_DIR}/photos/index.html" ]; then if [ ! -d "${WEB_DIR}/photos" ] || [ ! -f "${WEB_DIR}/photos/index.html" ]; then
echo "==> Downloading pre-built web app..."
# Try to download web app
if curl -L -o /tmp/web.zip "https://github.com/ente-io/ente/releases/latest/download/web.zip" 2>/app/data/logs/curl_web.log; then
echo "==> Web app download successful, extracting..."
# Check if it's a valid zip file
if file /tmp/web.zip | grep -q "Zip archive data"; then
mkdir -p /tmp/web
unzip -o /tmp/web.zip -d /tmp/web
# Check if extraction was successful
if [ -d "/tmp/web" ]; then
# Copy contents to the web directory
cp -r /tmp/web/* ${WEB_DIR}/ || echo "Failed to copy web files"
echo "==> Web app extracted and installed"
else
echo "==> Failed to extract web app"
fi
else
echo "==> Downloaded file is not a valid zip file: $(file /tmp/web.zip)"
fi
else
echo "==> Web app download failed, trying with wget..."
if wget -O /tmp/web.zip "https://github.com/ente-io/ente/releases/latest/download/web.zip" 2>/app/data/logs/wget_web.log; then
echo "==> Web app download with wget successful, extracting..."
# Check if it's a valid zip file
if file /tmp/web.zip | grep -q "Zip archive data"; then
mkdir -p /tmp/web
unzip -o /tmp/web.zip -d /tmp/web
# Copy contents to the web directory
cp -r /tmp/web/* ${WEB_DIR}/ || echo "Failed to copy web files"
echo "==> Web app extracted and installed"
else
echo "==> Downloaded file is not a valid zip file: $(file /tmp/web.zip)"
fi
else
echo "==> Web app download with wget also failed, creating placeholders"
fi
fi
# If download failed, try to manually copy from repository
if [ ! -f "${WEB_DIR}/photos/index.html" ] && [ -d "$ENTE_DIR/web/apps/photos/out" ]; then
echo "==> Copying pre-built web apps from repository..."
mkdir -p "${WEB_DIR}/photos"
cp -r "$ENTE_DIR/web/apps/photos/out/"* "${WEB_DIR}/photos/" || echo "Failed to copy photos app"
if [ -d "$ENTE_DIR/web/apps/accounts/out" ]; then
mkdir -p "${WEB_DIR}/accounts"
cp -r "$ENTE_DIR/web/apps/accounts/out/"* "${WEB_DIR}/accounts/" || echo "Failed to copy accounts app"
fi
if [ -d "$ENTE_DIR/web/apps/auth/out" ]; then
mkdir -p "${WEB_DIR}/auth"
cp -r "$ENTE_DIR/web/apps/auth/out/"* "${WEB_DIR}/auth/" || echo "Failed to copy auth app"
fi
if [ -d "$ENTE_DIR/web/apps/cast/out" ]; then
mkdir -p "${WEB_DIR}/cast"
cp -r "$ENTE_DIR/web/apps/cast/out/"* "${WEB_DIR}/cast/" || echo "Failed to copy cast app"
fi
echo "==> Copied web apps from repository"
fi
# Create placeholder HTML if download and build both failed
if [ ! -f "${WEB_DIR}/photos/index.html" ]; then
echo "==> Creating placeholder HTML files..." echo "==> Creating placeholder HTML files..."
mkdir -p ${WEB_DIR}/photos mkdir -p ${WEB_DIR}/photos
cat > ${WEB_DIR}/photos/index.html << 'EOF' cat > ${WEB_DIR}/photos/index.html << 'EOF'
@ -353,7 +339,6 @@ EOF
sed -i 's/Photos/Cast/g' ${WEB_DIR}/cast/index.html sed -i 's/Photos/Cast/g' ${WEB_DIR}/cast/index.html
echo "==> Created placeholder HTML files" echo "==> Created placeholder HTML files"
fi
else else
echo "==> Ente web app already set up" echo "==> Ente web app already set up"
fi fi
@ -396,7 +381,7 @@ done
# Set up Caddy web server # Set up Caddy web server
echo "==> Setting up Caddy web server..." echo "==> Setting up Caddy web server..."
cat > /app/data/Caddyfile << EOF cat > /app/data/Caddyfile << EOF
:80 { :3080 {
log { log {
output file /app/data/logs/caddy.log output file /app/data/logs/caddy.log
} }
@ -447,11 +432,19 @@ echo "==> Created Caddy configuration"
# Start Caddy web server # Start Caddy web server
echo "==> Starting Caddy web server..." echo "==> Starting Caddy web server..."
caddy run --config /app/data/Caddyfile > /app/data/logs/caddy.log 2>&1 & caddy run --config /app/data/Caddyfile > /app/data/logs/caddy.log 2>&1 &
echo "==> Caddy web server started" CADDY_PID=$!
echo "==> Caddy web server started with PID: $CADDY_PID"
# Keep script running
echo "==> Setup complete, entering wait loop..."
# Remove the flag file to indicate that we've started successfully # Remove the flag file to indicate that we've started successfully
rm -f /app/data/startup_in_progress rm -f /app/data/startup_in_progress
echo "==> Setup complete, everything is running."
# Verify services are running
echo "==> Verifying services..."
ps aux | grep node | grep -v grep || echo "WARNING: Node.js server not running!"
ps aux | grep caddy | grep -v grep || echo "WARNING: Caddy server not running!"
# Keep script running
echo "==> Entering wait loop to keep container alive..."
# Keep the script running to prevent container exit # Keep the script running to prevent container exit
tail -f /app/data/logs/museum.log tail -f /app/data/logs/museum.log