~ekez/negativefour

a3ba218efef2773e5826b94d9ca3c096795b3ddc — Zeke Medley a month ago 8ac6412
Fix race condition between apache restart and status check

After a delete job is submitted the user is redirected to the status
page. For the undeploy script it runs fast enough that during the
moment the user is redirected the script may restart apache causing
errors for the visitor. This "resolves" that by adding a three second
sleep to deletion like in deploy.sh.
5 files changed, 15 insertions(+), 7 deletions(-)

M serve/app.js
M serve/deploy.sh
M serve/undeploy.sh
M www/routes/deploy.js
M www/routes/status.js
M serve/app.js => serve/app.js +2 -2
@@ 142,10 142,10 @@ app.get('/status', requireAuth, function(req, res) {
	})
    }

    jobInfo = jobStatusMap.get(jobID)
    const jobInfo = jobStatusMap.get(jobID)

    if (!jobInfo) {
	res.status(404).json({
	return res.status(404).json({
	    error: 'No such job.'
	})
    }

M serve/deploy.sh => serve/deploy.sh +1 -1
@@ 38,7 38,7 @@ URL="$NAME.negativefour.app"

git clone "$REPO" "/home/admin/www/html/$URL"

PORT=$((3000 + `ls /etc/apache2/sites-available/ | wc -l`))
PORT=$((3100 + `ls /etc/apache2/sites-available/ | wc -l`))

cat <<EOF >> "/etc/tor/torrc"
HiddenServiceDir /var/lib/tor/${URL}/

M serve/undeploy.sh => serve/undeploy.sh +7 -0
@@ 42,6 42,13 @@ rm -rf "/var/lib/tor/${URL}"

systemctl restart tor

# If we don't have this sleep an interesting race condition occurs
# where apache will be restarting as the user tries to check the
# status of the build causing the first check to fail. This quick
# check happens because after a delete operation the user is instantly
# redirected to the status page.
sleep 3

rm "/etc/apache2/sites-available/${URL}.conf"

a2dissite "${URL}"

M www/routes/deploy.js => www/routes/deploy.js +2 -2
@@ 45,8 45,8 @@ router.post('/', requireAuth, async function(req, res, next) {
	    message: '500 - Server error communicating with serve api',
	    userEmail: req.useremail,
	    error: {
		status: `An error occured while processing a deploy action for user (${user}) and webpage (${name})`,
		stack: req.url,
		status: `An error occured while processing a deploy action for user (${user}) and webpage (${name}): (${err})`,
		stack: err.stack,
	    }
	})
    }

M www/routes/status.js => www/routes/status.js +3 -2
@@ 30,7 30,7 @@ router.get('/:jobID/:name/:type', requireAuth, async function(req, res, next) {
    const jobID = req.params.jobID
    const name = req.params.name

    // Type is either deploy or undeploy
    // Type is either deploy or delete
    const type = req.params.type

    const signedData = jwt.sign({


@@ 85,11 85,12 @@ ${deployments}`,
	    userEmail: req.useremail
	})
    } catch (err) {
	console.log(`error getting status ${err}`)
	return res.status(500).render('error', {
	    message: '500 - Internal Server Error',
	    error: {
		status: 'An error occured getting the build status. Please send Zeke an email if this persists.',
		stack: err,
		stack: err.stack,
		userEmail: req.useremail
	    }
	})