chadek commented on PR #44470:
URL: https://github.com/apache/superset/pull/44470#issuecomment-5769625264
Thanks @rusackas — both directions of that race were real, and you were
right that it isn't a one-line fix while the `catch` doubles as "build vs bail"
for the whole function's return value. Rebased onto current master and pushed;
here's where each point landed.
**The stale initial fetch tearing down an embed a reload already
recovered.** The teardown is now gated on whether anything has taken over the
token chain:
```ts
if (generation === 0) {
teardown("the initial guest token fetch failed");
throw err;
}
log("the initial guest token fetch failed, a reload has taken over:", err);
```
A reload opens a token cycle of its own, and that cycle — not this one —
decides whether the embed lives: it either hands the document in front of the
user a token, or retries until it can. Guarding on `generation` rather than on
"has a token actually arrived" also covers the narrower window where the
reload's own fetch is still in flight when the initial one rejects; tearing
down there would kill the embed microseconds before it recovers.
`embedDashboard` then resolves normally rather than rethrowing.
**The other direction — a valid initial token thrown away for a 10s retry.**
`deliverGuestToken` hands a superseded token over when the current document has
none:
```ts
const ownsChain = gen === generation;
if (ownsChain || !connection.tokenSent) { /* emit */ }
if (ownsChain) { armRefresh(/* … */); }
```
Any valid token gets that document rendering, and only the cycle that owns
the chain arms a timer, so two cycles overlapping across a reload still can't
leave two timers running.
**The `load` listener re-authenticating on any load** — not as harmless as
it looked, so thanks for flagging it. It was minting tokens for documents that
can never use one. The SDK now confirms the handshake before asking the host
for anything: it calls a method the embedded page deliberately does not
implement, and the `Method "..." is not defined` error every version of the
page replies with is itself the acknowledgement. Silence times out at 5s and no
token is fetched. A link in a Markdown chart pointing at a plain Superset URL,
or off site, now costs the host's endpoint nothing, and coming back to the
dashboard re-authenticates as usual.
**The smaller two.** `hostMethods`/`defineHostMethod` no longer use `any` —
the registry is `HostMethod = (args: never) => unknown` with a generic
`defineHostMethod<A extends object>`, so each method keeps its own signature at
the call site and no cast is needed. Tests are flattened to top-level `test()`s
named in the `reload …` / `unmount …` style already used in the file; ten of
them now.
**Heads-up on what else grew here since you reviewed.** Your comments were
against the version that still kept a bare `ourPort`. A `Connection` now
bundles a port with everything scoped to the document behind it, which brought
in two things worth a look: a `get` still in flight when the document leaves is
rejected with `PortClosedError` instead of hanging forever on a reply that can
no longer come (same for `unmount()`), and the theme pushed with
`setThemeConfig`/`setThemeMode` is replayed to the new document after its token
— methods were being replayed but state wasn't, so the dashboard came back in
the default theme.
**On verification.** The unit tests mock `MessageChannel` and `Switchboard`,
which is precisely the layer these bugs live in, so I also built a local test
rig to check the parts that only exist between two documents: a host app and a
stand-in for the embedded page on two origins, driven in headless Chromium
against the built UMD bundle over the real `@superset-ui/switchboard`, no npm
dependencies beyond a chromium binary. 39 checks, including both directions of
this race — it reaches them by holding the first `fetchGuestToken()` open while
the dashboard navigates, which is not otherwise reachable with an endpoint that
answers promptly.
I confirmed each fix by reverting it and watching the matching check go red:
- dropping the `generation === 0` guard → *"the working dashboard is not
torn down"* and *"embedDashboard resolves rather than rejecting"* fail
- dropping `|| !connection.tokenSent` → *"the superseded token is handed
straight to the current document"* fails, bounded to 3s on purpose: a token
that only turns up on the 10s retry is exactly the blank page this is about
It also covers the theme replay, the `PortClosedError` paths, and that a
navigation away from the embedded page mints nothing. I've kept it out of this
diff to hold the review surface to the fix itself, but I'm glad to push it as a
follow-up commit here or as its own PR if you think it earns its place — it's
the only thing I have that exercises the cross-document behaviour for real.
Happy to refresh the PR description too, since it predates the handshake
probe and the `PortClosedError` work.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]