Skip to content

Commit

Permalink
Deliver Alert Banner data with environment polling (#404)
Browse files Browse the repository at this point in the history
+ For use with corresponding hoist-react change xh/hoist-react@645cc60
  • Loading branch information
lbwexler authored Sep 17, 2024
1 parent 6f7fae6 commit d90f839
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 15 deletions.
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()
}
}

0 comments on commit d90f839

Please sign in to comment.