Skip to content

Commit

Permalink
web: optimize offline shard checker (#1708)
Browse files Browse the repository at this point in the history
* web: add per-guild status endpoint

* frontend: use new per-guild status endpoint

* frontend: store offline check timer on window
  • Loading branch information
jo3-l authored Jul 22, 2024
1 parent b9dabf9 commit 61058ff
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 16 deletions.
29 changes: 13 additions & 16 deletions frontend/templates/cp_main.html
Original file line number Diff line number Diff line change
Expand Up @@ -168,20 +168,19 @@ <h2 class="card-title">
});

{{if .ActiveGuild}}
async function runShardOfflineChecker() {
let wasOffline = await checkShardOffline();
let shardCheckerRunning = sessionStorage.getItem('isShardOfflineCheckerRunning');
if (shardCheckerRunning === 'true') {
return;
async function startShardOfflineChecker() {
if (typeof window.offlineShardCheckerInterval !== 'undefined') {
clearInterval(window.offlineShardCheckerInterval);
}
sessionStorage.setItem('isShardOfflineCheckerRunning', 'true');
setInterval(async () => {
const currentlyOffline = await checkShardOffline();

let wasOnline = await checkGuildShardOnline();
window.offlineShardCheckerInterval = setInterval(async () => {
const currentlyOnline = await checkGuildShardOnline();

// To prevent spurious warnings during routine shard reconnections,
// only show an alert if a shard appears to be offline for two
// checks in a row.
if (wasOffline && currentlyOffline) {
if (!wasOnline && !currentlyOnline) {
upsertAlert(
"The shard the bot is on for your server is currently offline; some functionality may not work as expected. \
Join the support server for more information if this issue persists."
Expand All @@ -190,14 +189,13 @@ <h2 class="card-title">
$("#shard-problems-warning").remove();
}

wasOffline = currentlyOffline;
wasOnline = currentlyOnline;
}, 15_000);
}

async function checkShardOffline() {
const data = await fetch("/status.json").then((resp) => resp.json());
const shardId = Number(BigInt("{{.ActiveGuild.ID}}") >> BigInt(22)) % data.total_shards;
return data.offline_shards && data.offline_shards.includes(shardId);
async function checkGuildShardOnline() {
const status = await fetch("/api/{{.ActiveGuild.ID}}/status.json").then((resp) => resp.json());
return status.shard_online;
}

function upsertAlert(msg) {
Expand All @@ -208,8 +206,7 @@ <h2 class="card-title">
}
}

// Computing the shard number requires BigInt support.
if (typeof BigInt !== "undefined") runShardOfflineChecker();
startShardOfflineChecker();
{{end}}
})
</script>
Expand Down
17 changes: 17 additions & 0 deletions web/handlers_general.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,23 @@ func HandleStatusJSON(w http.ResponseWriter, r *http.Request) interface{} {
return status
}

type GuildStatus struct {
ShardOnline bool `json:"shard_online"`
}

// HandleGuildStatusJSON handles GET /api/:server/status.json
func HandleGuildStatusJSON(w http.ResponseWriter, r *http.Request) interface{} {
g := r.Context().Value(common.ContextKeyCurrentGuild).(*dstate.GuildSet)
status, err := getFullBotStatus()
if err != nil {
return err
}

shard := int(g.ID>>22) % status.TotalShards
isOffline := common.ContainsIntSlice(status.OfflineShards, shard)
return GuildStatus{ShardOnline: !isOffline}
}

type HostStatus struct {
Name string

Expand Down
1 change: 1 addition & 0 deletions web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ func setupRoutes() *goji.Mux {
RootMux.Handle(pat.Get("/api/:server/*"), ServerPublicAPIMux)

ServerPublicAPIMux.Handle(pat.Get("/channelperms/:channel"), RequireActiveServer(APIHandler(HandleChannelPermissions)))
ServerPublicAPIMux.Handle(pat.Get("/status.json"), RequireActiveServer(APIHandler(HandleGuildStatusJSON)))

// Server selection has its own handler
RootMux.Handle(pat.Get("/manage"), SelectServerHomePageHandler)
Expand Down

0 comments on commit 61058ff

Please sign in to comment.