S
SolidJS2mo ago
zimo

Cache server variable separately in db, server, front-end

So I have the idea to be able to "lock" my database for maintenance I sometimes do offline. My idea is thus to have a "locked" setting in a persistent settings table in my database. On startup, the server should read this setting and set a server-side variable based on it, let's called it isDbLocked. I would then like the front end to be able to read this server-side variable to disable some UI elements. An admin should then be able to change this variable through the UI. Which in turn tries to update the database. If successful, it updates the server-side variable, and thus the front end too (maybe makes a new explicit request here to update it). My question is how to do this in practice in SolidStart? I tried something like just having a .ts file with a isDbLocked variable, then an init function that queries the db on server init. But I can't just import and use isDbLocked probably... I would need to fetch it from the server? Should I createResource or "use server"? Also is this overly complicated? Should I just always make requests that always read the db and returns the setting instead of having an intermediate server-side variable? My idea was to reduce requests to the DB since we always know the value of isDbLocked. It's only ever changed when an admin changes it.
1 Reply
zimo
zimo2mo ago
I have done this so far: serverLock.ts:
import { getSettingServer, getUserSession, isAdmin, setSettingServer } from "./databse";

export let isDbLocked = true;

// Function to set the lock state, both in memory and the database
export async function setLockState(newState: boolean) {
"use server"
const session = await getUserSession();
if (!isAdmin(session))
return;

const updatedCorrectly = await setSettingServer("lockDb", newState.toString());
if (updatedCorrectly)
isDbLocked = newState;

console.log("isLocked is now " + isDbLocked);
return updatedCorrectly;
}

// Initialize the lock state from the database when the server starts
export async function initializeLockState() {
// "use server"
const dbValue = await getSettingServer("lockDb");
if (dbValue !== undefined) {
isDbLocked = dbValue === "true";
}
else {
await setSettingServer("lockDb", isDbLocked.toString())
}
}
import { getSettingServer, getUserSession, isAdmin, setSettingServer } from "./databse";

export let isDbLocked = true;

// Function to set the lock state, both in memory and the database
export async function setLockState(newState: boolean) {
"use server"
const session = await getUserSession();
if (!isAdmin(session))
return;

const updatedCorrectly = await setSettingServer("lockDb", newState.toString());
if (updatedCorrectly)
isDbLocked = newState;

console.log("isLocked is now " + isDbLocked);
return updatedCorrectly;
}

// Initialize the lock state from the database when the server starts
export async function initializeLockState() {
// "use server"
const dbValue = await getSettingServer("lockDb");
if (dbValue !== undefined) {
isDbLocked = dbValue === "true";
}
else {
await setSettingServer("lockDb", isDbLocked.toString())
}
}
Then I can use it like this in the frontend:
import { createAsync } from "@solidjs/router";
import "./MaintenanceMessage.css";
import { Show } from "solid-js";
import { isDbLocked } from "~/server/serverLock";

const MaintenanceMessage = () => {
const isLockedLocal = createAsync(async () => {
"use server"
return isDbLocked;
});

return <Show when={isLockedLocal()}>
<div class="info-box">[Site is under maintenance]
<span class="info-text">The site is in read-only mode. <br />Some functions like voting/submitting are temporarily disabled.</span>
</div>
</Show>;
};

export default MaintenanceMessage;
import { createAsync } from "@solidjs/router";
import "./MaintenanceMessage.css";
import { Show } from "solid-js";
import { isDbLocked } from "~/server/serverLock";

const MaintenanceMessage = () => {
const isLockedLocal = createAsync(async () => {
"use server"
return isDbLocked;
});

return <Show when={isLockedLocal()}>
<div class="info-box">[Site is under maintenance]
<span class="info-text">The site is in read-only mode. <br />Some functions like voting/submitting are temporarily disabled.</span>
</div>
</Show>;
};

export default MaintenanceMessage;
This works well, but I don't want to keep defining isLockedLocal in all my components. I would have hoped I could create sort of a global variable that I could use. But defining it in a globalStore.ts and exporting it I get weird errors because of createAsync() being defined outside a route I guess. Also isLockedLocal doesn't update in realtime. I will have to refresh the website to see the updates. I would prefer it more if isLockedLocal worked more like a global signal. What's the best practice here?
Want results from more Discord servers?
Add your server