Merge pull request 'fix(assets): a busy shard is not a broken one, and a column that reached no existing install (Phase 9a)' (#42) from feat/asset-bridge-p9 into edge
Reviewed-on: #42
This commit is contained in:
@@ -13,6 +13,7 @@ module that follows.
|
||||
│ module-uo (>>> HERE <<<) │
|
||||
│ shard status · spawn atlas · marketplace │
|
||||
│ governors · cliloc · town crier · uo-link│
|
||||
│ client files: portraits, item art, names │
|
||||
└───────────────────────────────────────────┘
|
||||
│ server half: routers, models, schema fragment
|
||||
│ client half: prebuilt ESM chunk, SPA routes + nav
|
||||
@@ -182,7 +183,7 @@ reaches the container.
|
||||
|---|---|---|
|
||||
| `UOLINK_BASE_URL` | — | Default sidecar base URL for a site with nothing saved yet. The admin panel's stored value wins. |
|
||||
| `UOLINK_WS_URL` | — | Same, for the WebSocket URL. |
|
||||
| `UOLINK_PROTOCOL` | `3` | Wire protocol this build speaks. Again only a fallback — set it lower only if you deliberately run an older sidecar. |
|
||||
| `UOLINK_PROTOCOL` | `8` | Wire protocol this build speaks. Again only a fallback — set it lower only if you deliberately run an older sidecar. |
|
||||
| `TOWNCRIER_DURATION_SEC` | `3600` | How long a published news post's in-game town-crier message stays up (≤ `86400`). |
|
||||
|
||||
**The sidecar's auth token is deliberately not here.** It is entered in Admin → Shard, encrypted at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import api from '../../api.js'
|
||||
import { ErrorState, Loading } from '../../core.js'
|
||||
import Row from '../../components/DetailRow.jsx'
|
||||
@@ -245,6 +245,28 @@ export default function ClientFiles() {
|
||||
load()
|
||||
}, [load])
|
||||
|
||||
// One automatic re-read when the shard answered BUSY (§3.2's single slot),
|
||||
// and exactly one per mount.
|
||||
//
|
||||
// BUSY is not a fault and it is not sticky on the shard — it means something
|
||||
// else held the asset slot for longer than the client's own 425 backoff, and
|
||||
// the two things that hold it are both ordinary: an import the operator
|
||||
// started, and the item-art warm pass refilling itself after a client patch.
|
||||
// The panel does not poll, so without this the operator is left reading a
|
||||
// refusal about a shard that was free again seconds later, until they think to
|
||||
// reload. A second read clears the common case; if it is still busy, the
|
||||
// sentence says to come back, because a page that retried forever would be
|
||||
// holding the slot it is waiting for.
|
||||
const retried = useRef(false)
|
||||
useEffect(() => {
|
||||
if (retried.current || busy) return
|
||||
const stillBusy = assets?.code === 'BUSY' || clilocs?.code === 'BUSY'
|
||||
if (!stillBusy) return
|
||||
retried.current = true
|
||||
const t = setTimeout(() => load({ quiet: true }), 4000)
|
||||
return () => clearTimeout(t)
|
||||
}, [assets, clilocs, busy, load])
|
||||
|
||||
// Every action shares this: run it, say what it said, then re-read status so
|
||||
// the panel reflects the world rather than what we assumed happened.
|
||||
async function run(section, table, fn) {
|
||||
@@ -347,9 +369,22 @@ export default function ClientFiles() {
|
||||
style={{ border: '1px solid var(--line)', borderRadius: 10, padding: 16 }}
|
||||
className="sans"
|
||||
>
|
||||
<strong style={{ color: 'var(--head)' }}>The shard is not answering for client files.</strong>
|
||||
{/* BUSY is the one code here that is not a fault, and saying "the shard
|
||||
is not answering" about it sends an operator to check a shard that is
|
||||
working. The slot is held by something ordinary — an import running,
|
||||
or the warm pass — and it frees itself. */}
|
||||
<strong style={{ color: 'var(--head)' }}>
|
||||
{assets.code === 'BUSY'
|
||||
? 'The shard is busy with another client-file request.'
|
||||
: 'The shard is not answering for client files.'}
|
||||
</strong>
|
||||
<p style={{ margin: '6px 0 0', color: 'var(--muted)', fontSize: '0.86rem', lineHeight: 1.6 }}>
|
||||
{assets.reason}
|
||||
{assets.code === 'BUSY'
|
||||
? 'The shard serves one of these at a time, so an import running now — or the' +
|
||||
' item-picture pass refilling itself after a client patch — holds it until it is' +
|
||||
' done. This page re-reads once on its own; if the counts below are still missing' +
|
||||
' after that, reload in a moment.'
|
||||
: assets.reason}
|
||||
{assets.code === 'DISABLED' &&
|
||||
' — set Bridge.AssetsEnabled on the shard to allow it to read its own client files.'}
|
||||
</p>
|
||||
|
||||
@@ -957,3 +957,20 @@ UPDATE uo_link_config SET protocol = 8
|
||||
WHERE id = 1 AND protocol < 8
|
||||
AND NOT EXISTS (SELECT 1 FROM settings WHERE `key` = 'uo_link_protocol_8_migrated');
|
||||
INSERT IGNORE INTO settings (`key`, value) VALUES ('uo_link_protocol_8_migrated', '1');
|
||||
|
||||
-- `shard_spawn_points.unique_id` for an install that already had the table
|
||||
-- (Asset Bridge phase 9; the column itself is Events phase 12b).
|
||||
--
|
||||
-- The column was added to the CREATE TABLE above and nowhere else, so it reached
|
||||
-- fresh installs and no existing one -- `CREATE TABLE IF NOT EXISTS` does not add
|
||||
-- a column to a table that is already there, which is what every ALTER in this
|
||||
-- file exists to do. `replaceAtlas` inserts `unique_id` unconditionally, so on an
|
||||
-- upgraded install EVERY spawn-atlas import since v1.2.0 has failed outright with
|
||||
-- `Unknown column 'unique_id' in 'INSERT INTO'` -- the bestiary, the spawn map and
|
||||
-- the champion altars all frozen at whatever was last imported.
|
||||
--
|
||||
-- Found by the phase 9 acceptance walk, on a rig whose tables predate 12b: a fresh
|
||||
-- install cannot reproduce it, and neither can a test whose schema is this file
|
||||
-- applied to an empty database. That is the same blind spot the protocol-pin block
|
||||
-- above records, two phases running.
|
||||
ALTER TABLE shard_spawn_points ADD COLUMN IF NOT EXISTS unique_id VARCHAR(64) NULL;
|
||||
|
||||
Reference in New Issue
Block a user