putyourlightson / craft-sprig

A reactive Twig component framework for Craft CMS.
https://putyourlightson.com/plugins/sprig
MIT License
129 stars 9 forks source link

How to stop polling on sprig control panel page when in maintenance mode? #357

Closed bossanova808 closed 7 months ago

bossanova808 commented 7 months ago

I have a control panel page that refreshes a toolbar section with polling:

<span id="trigger-toolbar" style="display:none;" sprig s-trigger="every 5s"></span>

However, if the site is in maintenance mode, this immediately causes the web.log to fill up with hundreds of these:

2024-03-19 11:47:55 [web.ERROR] [yii\web\HttpException:503] Your account doesn’t have permission to access the control panel when the system is offline.

HTMX says to send a 286 response code to stop polling but I can't see how I can do this as Craft gets in first.

Any ideas on how one might tackle this? (Without my hoped for server side events, I am forced to use polling here!)

bencroker commented 7 months ago

Couldn’t you only poll when Craft is not in maintenance mode?

{% if not craft.app.isInMaintenanceMode %}
    ...
{% endif %}
bossanova808 commented 7 months ago

Sorry I am mixing up my lingo from the old days - not maintenance mode, rather with the system offline.

That leads me to craft.app.isSystemLive but that gives a twig error (although it seems like it shouldn't to me?)

Anyway, this seems to be it, but it doesn't stop the polling, so I guess not?

{% if not craft.app.config.general.isSystemLive %}
    <span id="trigger-toolbar" style="display:none;" sprig s-trigger="every 5s"></span>
{% endif %}
bossanova808 commented 7 months ago

Ergh sorry, of course the boolean needs to be reversed.

{% if craft.app.config.general.isSystemLive %}

..but that doesn't work as I think that's the PC value. Hmmm.

bencroker commented 7 months ago

That should work. If it doesn’t then the issue is on Craft, not on Sprig.

bossanova808 commented 7 months ago

Apparently it is isLive not isSystemLive as the class docs seem to imply

{% if craft.app.isLive %}
    <span id="trigger-toolbar" style="display:none;" sprig s-trigger="every 5s"></span>
{% endif %}

...is what is needed. And works because in this case it's reloading the whole page (of course it won't resume polling when switch back on but this achieves the main goal!).

Thanks Ben!

bossanova808 commented 7 months ago

A very similar/related questions.

Say I have one window with this toolbar active and refreshing via polling.

In another window, I log out of the control panel. Then, in the first window (and endlessly in the web.log) I start seeing:

image

"#0 /home/forge/imagescience.com.au/releases/dev/vendor/yiisoft/yii2/base/Controller.php(176): putyourlightson\\sprig\\controllers\\ComponentsController->beforeAction(Object(yii\\base\\InlineAction))",
"#1 /home/forge/imagescience.com.au/releases/dev/vendor/yiisoft/yii2/base/Module.php(552): yii\\base\\Controller->runAction('...', Array)",
"#2 /home/forge/imagescience.com.au/releases/dev/vendor/craftcms/cms/src/web/Application.php(341): yii\\base\\Module->runAction('...', Array)",
"#3 /home/forge/imagescience.com.au/releases/dev/vendor/craftcms/cms/src/web/Application.php(642): craft\\web\\Application->runAction('...', Array)",
"#4 /home/forge/imagescience.com.au/releases/dev/vendor/craftcms/cms/src/web/Application.php(303): craft\\web\\Application->_processActionRequest(Object(craft\\web\\Request))",
"#5 /home/forge/imagescience.com.au/releases/dev/vendor/yiisoft/yii2/base/Application.php(384): craft\\web\\Application->handleRequest(Object(craft\\web\\Request))",
"#6 /home/forge/imagescience.com.au/releases/dev/web/index.php(12): yii\\base\\Application->run()",
"#7 {main}"],"memory":9814296,"exception":"[object] (Error(code: 0): Call to a member function can() on null at /home/forge/imagescience.com.au/releases/dev/vendor/putyourlightson/craft-sprig-core/src/controllers/ComponentsController.php:33)"}

Would it be possible/appropriate for Sprig to perhaps detect and intercept this issue, and return the HTTP 426 response code required to stop the polling?

I don't think there's another mechanism here (e.g. wrapping in if currentUser or similar) - because the page reload won't happen due to this error. But perhaps I missing some obvious mechanism here?

(We sometimes have machines left on overnight, user is logged out for inactivitiy, and then this goes on for the next 12 hours and many megabytes of log clutter...)

bencroker commented 7 months ago

Would it be possible/appropriate for Sprig to perhaps detect and intercept this issue, and return the HTTP 426 response code required to stop the polling?

I don’t think it would, because the system might be down for only a minute.

The most obvious solution would be act on an error response however you see fit.

<script>
    htmx.on('htmx:onLoadError', function(event) {
        // Show error, stop polling, etc.
    });
</script>

Reference: https://htmx.org/events/#htmx:onLoadError

bossanova808 commented 7 months ago

Ok, thanks Ben - looks like onResponseError is the one that is raised. If I then remove the span holding the trigger, the polling stops, and I can add a user message too.

bencroker commented 7 months ago

You’re right, the event is in fact htmx:responseError.

<script>
    htmx.on('htmx:responseError', function(event) {
        // Show error, stop polling, etc.
    });
</script>