sablierapp / sablier

Start your containers on demand, shut them down automatically when there's no activity. Docker, Docker Swarm Mode and Kubernetes compatible.
https://sablierapp.dev/
GNU Affero General Public License v3.0
1.36k stars 46 forks source link

Get X-Sablier-Session-Status header through the ingress #265

Closed c0da closed 7 months ago

c0da commented 7 months ago

I've created a custom theme with an animation that resets when the page reloads (every '.RefreshFrequency'). As this is not the behavior I am looking for, I thought it might be a good idea to load the theme as usual (with the animation) and make Ajax requests to some URL every "RefreshFrequency" asking for the status of 'X-Sablier-Session-Status' header (or similar), and when it's 'ready', just reload the entire page to access the real application.

Do you folks believe it could be possible in some way?

c0da commented 7 months ago

If it's helpful for anyone, this is what I ended up doing (perhaps not the most elegant solution in the world, but it works): I've created a hidden div listing the status of all processes:

<div id="instanceStatesContainer" style="display: none;">
    <ul>
        {{ range $i, $instance := .InstanceStates }}
            <li>{{ $instance.Status }}</li>
        {{ end }}
    </ul>
</div>

And then I make a GET request to "/" with javascript every .RefreshFrequency (*) to update the statuses and check how many are ok:

<script>
    function allReady() {
        fetch('/', {
            method: 'GET',
            cache: 'no-cache',
            headers: {
                'Cache-Control': 'no-cache',
            },
        }).then(response => {
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
            return response.text();
        }).then(data => {
            responseData = data;

            var parser = new DOMParser();
            var htmlDoc = parser.parseFromString(responseData, 'text/html');
            var divContent = htmlDoc.getElementById('instanceStatesContainer');

            if (divContent) {
                var liElements = divContent.querySelectorAll('li');
                for (var i = 0; i < liElements.length; i++) {
                    if (liElements[i].textContent.trim() !== "ready") {
                        // If at least one is not "ready", returns false
                        return false;
                    }
                }
            }
            location.reload();
        }).catch(error => {
            console.error('Error making the request:', error);
            return false; // Return false if there is an error in the request
        });
    }

    // Check if all processes are in "ready" state every RefreshFrequency seconds
    setInterval(allReady, {{ .RefreshFrequency }});
</script>

When all are 'ready', I refresh the page so the main application gets loaded.

(*) Note: In JavaScript, the refresh time is expressed in milliseconds, and the variable 'RefreshFrequency' accepts values like '5s' (which is then converted to 5). To check the status every 5 seconds, I had to set the RefreshFrequency variable to '5000s' (5000 milliseconds).

acouvreur commented 7 months ago

Hey! That's awesome! Would you like to open a PR to put what you did in the docs ? I will do it at some point otherwise, very nice trick.

I've also considered SSE, Server sent events. Which might be a better option.

c0da commented 7 months ago

Thank you @acouvreur!! and of course, it would be an honor to contribute to the documentation! I will try to do something tomorrow so that we can adapt it as you see fit.