Automating a Keep-Alive Probe for Deployed Apps
Problem
Streamlit cloud allows developers to easily host streamlit applications for free! However, public apps will eventually hibernate if unused for a period of time. This can result in an pesky and occasionally lengthy reboot time. See details
Solution
To make sure the app is always primed, I automated a keep alive
probe which opens the website and clicks on the “reset” button if visible. I leveraged puppeteer to navigate and interact with the webpage using a headless browser. Then I automated a cron-job using Github Actions.
Creating a Probe Script
First, create the probe script to poke the website and look for the relevant “wake-up” button:
// probe-action/probe.js
const puppeteer = require('puppeteer');
const TARGET_URL = "https://<YOUR_STREAMLIT_APP_URL>.streamlitapp.com/";
const WAKE_UP_BUTTON_TEXT = "app back up";
const PAGE_LOAD_GRACE_PERIOD_MS = 8000;
(async () => {
const browser = await puppeteer.launch(
{ args: ["--no-sandbox"] }
);
const page = await browser.newPage();
await page.goto(TARGET_URL);
// Wait a grace period for the application to load
await page.waitForTimeout(PAGE_LOAD_GRACE_PERIOD_MS);
const checkForHibernation = async (target) => {
// Look for any buttons containing the target text of the reboot button
const [button] = await target.$x(`//button[contains(., '${WAKE_UP_BUTTON_TEXT}')]`);
if (button) {
console.log("App hibernating. Attempting to wake up!");
await button.click();
}
}
await checkForHibernation(page);
const frames = (await page.frames());
for (const frame of frames) {
await checkForHibernation(frame);
}
await browser.close();
})();
Dockerize
Next, create a very simple dockerfile from an existing puppeteer image. Its only job is to run the probe script:
# probe-action/Dockerfile
FROM ghcr.io/puppeteer/puppeteer:17.0.0
COPY . /home/pptruser/src
ENTRYPOINT [ "/bin/bash", "-c", "node -e \"$(</home/pptruser/src/probe.js)\"" ]
You can test it locally like so:
docker build -t probe:latest .
docker run -it --rm probe:latest
Schedule a cron-job with Github Actions
Now we’ll setup the github action and cron-job to run this probe routinely.
The final repository for the streamlit app looks like this:
repo/ # The git repo deployed to streamlit cloud
.github/
workflows/
keep-alive.yml # The cron job
probe-action/ # The keep-alive action
Dockerfile
action.yml
probe.js
app.py # The streamlit app
Start by creating the action metadata file which Github Actions will use to build the docker image and run the script.
# probe-action/action.yml
name: "Probe Deployed App"
description: "Probes a deployed streamlit app."
runs:
using: "docker"
image: "Dockerfile"
Finally, create a workflow file .github/workflows/keep-alive.yml
. Every 2 days it will check out the repo and run the probe action.
# .github/workflows/keep-alive.yml
name: Trigger Probe of Deployed App on a CRON Schedule
on:
schedule:
# Runs "at minute 0 past every 48 hour" (see https://crontab.guru)... ie: every 2 days
- cron: '0 */48 * * *'
jobs:
probe_deployed_app:
runs-on: ubuntu-latest
name: A job to probe deployed app
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Probe Deployed App Action Step
uses: ./probe-action # Uses an action in the probe-action directory
id: probe
Comments