Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deliver Alert Banner data with environment polling #404

Merged
merged 11 commits into from
Sep 17, 2024
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

### ⚙️ Technical

* Enhanced the `xh/environmentPoll` payload to include any active Alert Banner spec. Clients running
`hoist-react >= 68` will leverage this to avoid an extra polling request.
* Exposed `/xh/ping` as whitelisted route for basic uptime/reachability checks. Retained legacy
`/ping` alias, but prefer this new path going forward.
* Improved handling + rendering of exceptions during authentication and authorization requests.
Expand Down
3 changes: 3 additions & 0 deletions grails-app/controllers/io/xh/hoist/impl/XhController.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ class XhController extends BaseController {
//----------------------
// Alert Banner
//----------------------
/**
* @deprecated - used by hoist-react <= 67, now nested within {@link #environmentPoll}.
*/
def alertBanner() {
renderJSON(alertBannerService.alertBanner)
}
Expand Down
4 changes: 2 additions & 2 deletions grails-app/init/io/xh/hoist/BootStrap.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ class BootStrap implements LogSupport {
],
xhAlertBannerConfig: [
valueType: 'json',
defaultValue: [enabled: true, interval: 30],
defaultValue: [enabled: true],
clientVisible: true,
groupName: 'xh.io',
note: 'Configures support for showing an app-wide alert banner.\n\nAdmins configure and activate alert banners from the Hoist Admin console. To generally enable this system, set "enabled" to true and "interval" to a positive value (in seconds) to control how often connected apps check for a new alert.'
note: 'Configures support for showing an app-wide alert banner.\n\nAdmins configure and activate alert banners from the Hoist Admin console. To generally enable this system, set "enabled" to true. The xhEnvPollConfig.interval config governs client polling for updates.'
],
xhAppInstances: [
valueType: 'json',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

package io.xh.hoist.alertbanner


import groovy.transform.CompileStatic
import io.xh.hoist.BaseService
import io.xh.hoist.cache.CachedValue
Expand All @@ -27,7 +26,9 @@ import static java.lang.System.currentTimeMillis
*
* This class uses a single {@link io.xh.hoist.jsonblob.JsonBlob} to persist its state.
* The published alert state is updated via the Hoist Admin console and is regularly refreshed
* on a timer to catch banner expiry.
* by EnvironmentService.
*
* For this service to be active, `xhAlertBannerConfig` config must be specified as `{enabled:true}`.
*/
@CompileStatic
class AlertBannerService extends BaseService {
Expand Down Expand Up @@ -101,10 +102,9 @@ class AlertBannerService extends BaseService {
// Implementation
//-----------------------------
private void readFromSpec() {
def conf = configService.getMap('xhAlertBannerConfig'),
newSpec = emptyAlert
def newSpec = emptyAlert

if (conf.enabled) {
if (configService.getMap('xhAlertBannerConfig').enabled) {
def spec = getAlertSpec(),
expires = spec.expires as Long

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,27 @@ import grails.plugins.GrailsPlugin
import grails.util.GrailsUtil
import grails.util.Holders
import io.xh.hoist.BaseService
import io.xh.hoist.alertbanner.AlertBannerService
import io.xh.hoist.config.ConfigService
import io.xh.hoist.util.Utils
import io.xh.hoist.websocket.WebSocketService


/**
* Service with metadata describing the runtime environment of Hoist and this application.
* For the AppEnvironment (e.g. Development/Production), reference `Utils.appEnvironment`.
*
* If you are simply looking to read the `AppEnvironment` (e.g. Development/Production), use
* the static {@link io.xh.hoist.util.Utils#getAppEnvironment} instead.
*/
class EnvironmentService extends BaseService {

ConfigService configService
WebSocketService webSocketService
AlertBannerService alertBannerService

private TimeZone _appTimeZone
private Map _pollResult

static clearCachesConfigs = ['xhAppTimeZone', 'xhEnvPollConfig']
static clearCachesConfigs = ['xhAppTimeZone']

/**
* Official TimeZone for this application - e.g. the zone of the head office or trading center.
Expand Down Expand Up @@ -66,6 +69,7 @@ class EnvironmentService extends BaseService {
appTimeZoneOffset: appTz.getOffset(now),
webSocketsEnabled: webSocketService.enabled,
instanceName: clusterService.instanceName,
alertBanner: alertBannerService.alertBanner,
pollConfig: configService.getMap('xhEnvPollConfig')
]

Expand All @@ -84,16 +88,17 @@ class EnvironmentService extends BaseService {
}

/**
* Report server version and instance identity to the client.
* Designed to be called frequently by client. Should be minimal and highly optimized.
* Report server version, instance identity, and any active alert banner to the client.
* Designed for rapid polling - keep this minimal and highly optimized.
*/
Map environmentPoll() {
return _pollResult ?= [
return [
appCode : Utils.appCode,
appVersion : Utils.appVersion,
appBuild : Utils.appBuild,
instanceName: clusterService.instanceName,
pollConfig : configService.getMap('xhEnvPollConfig'),
alertBanner : alertBannerService.alertBanner,
pollConfig : configService.getMap('xhEnvPollConfig')
]
}

Expand All @@ -119,7 +124,6 @@ class EnvironmentService extends BaseService {

void clearCaches() {
_appTimeZone = null
_pollResult = null
super.clearCaches()
}
}
Loading