#[shard] and #[procedure] mint their endpoint id with Uuid::new_v4() at macro expansion time, so every compilation produces new URLs. A browser tab left open across a deploy keeps polling the previous binary's id, and the new binary does not serve it.
Four builds of one unchanged source in an application I built produced four ids:
d646e935-433f-44a3-88ea-fe71155e2a28
68c1a3c6-...
a91567b3-...
65adb204-...
What the open tab does then, from the network log of a tab that was never reloaded:
POST /_topcoat/shards/a823c355-9fd9-438f-a470-0507653715a8 -> 200 (3ms, 969B)
POST /_topcoat/shards/a823c355-9fd9-438f-a470-0507653715a8 -> 200 (2ms, 963B)
... rebuild and restart ...
POST /_topcoat/shards/a823c355-9fd9-438f-a470-0507653715a8 -> 405 (0B)
The status is 405 rather than 404 when a catch-all page claims the path. The failure is silent in both cases: fetchAndReplace swaps the empty body in, so the fifteen rows on screen are deleted while the heading, the summary and the filter box outside the shard stay put. Nothing reaches the console and no request fails from the application's point of view. A control run confirms the rebuild causes it and not the restart: stopping and starting the same binary cost the open tab one refused connection, after which it kept polling the same URL and picked up a delivery four seconds later.
@AmeinEskinder reproduced this independently on examples/shard, three builds with only a comment changed, and found two things I had not:
#[procedure] has the same construction at procedure.rs:123, so a stale tab's button click fails the same way.
topcoat asset bundle compiles the crate, so the bundling step can mint fresh ids partway through a deploy sequence.
There is already a pattern for a stable opaque id in the tree: AssetId::new hashes the crate name, the source file and the asset path. Something equivalent over crate name, module path and ident would survive a rebuild while staying opaque.
One argument against determinism, which belongs in the decision rather than in a reviewer's head: a fresh id per build means a URL someone learned once stops working at the next deploy, and making ids deterministic makes that URL permanent. It is not protection either way, since the page hands the id to anyone who loads it, and shard endpoints need their own authorization regardless.
Related: #247 covers the swap that makes the failure silent, and the id churn is the other half of what an open tab experiences across a deploy.
#[shard]and#[procedure]mint their endpoint id withUuid::new_v4()at macro expansion time, so every compilation produces new URLs. A browser tab left open across a deploy keeps polling the previous binary's id, and the new binary does not serve it.Four builds of one unchanged source in an application I built produced four ids:
What the open tab does then, from the network log of a tab that was never reloaded:
The status is 405 rather than 404 when a catch-all page claims the path. The failure is silent in both cases:
fetchAndReplaceswaps the empty body in, so the fifteen rows on screen are deleted while the heading, the summary and the filter box outside the shard stay put. Nothing reaches the console and no request fails from the application's point of view. A control run confirms the rebuild causes it and not the restart: stopping and starting the same binary cost the open tab one refused connection, after which it kept polling the same URL and picked up a delivery four seconds later.@AmeinEskinder reproduced this independently on
examples/shard, three builds with only a comment changed, and found two things I had not:#[procedure]has the same construction atprocedure.rs:123, so a stale tab's button click fails the same way.topcoat asset bundlecompiles the crate, so the bundling step can mint fresh ids partway through a deploy sequence.There is already a pattern for a stable opaque id in the tree:
AssetId::newhashes the crate name, the source file and the asset path. Something equivalent over crate name, module path and ident would survive a rebuild while staying opaque.One argument against determinism, which belongs in the decision rather than in a reviewer's head: a fresh id per build means a URL someone learned once stops working at the next deploy, and making ids deterministic makes that URL permanent. It is not protection either way, since the page hands the id to anyone who loads it, and shard endpoints need their own authorization regardless.
Related: #247 covers the swap that makes the failure silent, and the id churn is the other half of what an open tab experiences across a deploy.