ENG-1300 Publish relations when a node is published#827
Conversation
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
|
||
| const skipPublishAccess = | ||
| commonGroups.length > 0 && lastModified <= lastModifiedDb; | ||
| existingPublish.contains(myGroup) && lastModified <= lastModifiedDb; |
There was a problem hiding this comment.
JavaScript arrays don't have a .contains() method. This will throw a runtime error when determining whether to skip publish access.
// Current (broken):
existingPublish.contains(myGroup) && lastModified <= lastModifiedDb;
// Fixed:
existingPublish.includes(myGroup) && lastModified <= lastModifiedDb;| existingPublish.contains(myGroup) && lastModified <= lastModifiedDb; | |
| existingPublish.includes(myGroup) && lastModified <= lastModifiedDb; |
Spotted by Graphite Agent
Is this helpful? React 👍 or 👎 to let us know.
8cf253a to
9119d2f
Compare
9926af2 to
216f017
Compare
| const commonGroups = existingPublish.filter((g) => myGroups.has(g)); | ||
| // temporary single-group assumption | ||
| const myGroup = (commonGroups.length > 0 ? commonGroups : [...myGroups])[0]!; | ||
| return await publishNodeToGroup({ plugin, file, frontmatter, myGroup }); |
There was a problem hiding this comment.
Re publishNodeRelations blocking publishNode: I am not sure it's an error. Basically, if we throw here, the user knows the node is not published, and may try again. Otherwise, the node will be said to be published, and we won't have another opportunity to know to publish the relations.
There was a problem hiding this comment.
(Could fail silently after we create the scan for unpublished relations.)
e01f542 to
18be22b
Compare
a6034d5 to
024a9ee
Compare
trangdoan982
left a comment
There was a problem hiding this comment.
Except the nit i think this lgtm. This handles the cases where relations are newly created, when a new node is published well.
we should still have a documentation somewhere of all the current cases that we're handling publishing relations right now. maybe we should add it in the official doc or as a README in the publish folder?!
|
Re the documentation: I think it belongs in the main documentation. |
| try { | ||
| const published = await publishNewRelation(plugin, instance); | ||
| if (published) { | ||
| // save again with publication data | ||
| await saveRelations(plugin, data); | ||
| } |
There was a problem hiding this comment.
🔴 Stale data object saved after long-running publishNewRelation, overwriting concurrent relation changes
In addRelationNoCheck, the data object is loaded from disk at line 116. After saving the new relation at line 119, the long-running publishNewRelation is called at line 121, which internally runs a full syncAllNodesAndRelations involving multiple network requests (can take seconds). After it returns, data is saved again at line 124 to persist the publishedToGroupId update.
Root Cause and Impact
The data object at line 124 was loaded at line 116, before the sync started. If any other async operation modifies the relations file during the sync window (e.g., another addRelation, removeRelationById, or publishNodeRelations from publishNode.ts:214-230), save #2 at line 124 overwrites those changes with the stale data snapshot — losing any concurrently added/removed relations.
Before this PR, addRelationNoCheck had a trivial load→modify→save window (microseconds). Now the window spans the entire publishNewRelation call including syncAllNodesAndRelations(plugin, context, true) at apps/obsidian/src/utils/publishNode.ts:124, which collects all vault nodes, queries Supabase timestamps, filters relation concepts, and performs an RPC upsert — significantly widening the race window.
The fix is to re-load fresh data before save #2 instead of reusing the stale data:
if (published) {
const freshData = await loadRelations(plugin);
const rel = freshData.relations[id];
if (rel) {
rel.publishedToGroupId = instance.publishedToGroupId;
await saveRelations(plugin, freshData);
}
}Impact: Any relation created, deleted, or modified by a concurrent async operation during the publishNewRelation window will be silently lost when the stale data is written back to disk.
| try { | |
| const published = await publishNewRelation(plugin, instance); | |
| if (published) { | |
| // save again with publication data | |
| await saveRelations(plugin, data); | |
| } | |
| try { | |
| const published = await publishNewRelation(plugin, instance); | |
| if (published) { | |
| // re-load fresh data to avoid overwriting concurrent changes | |
| const freshData = await loadRelations(plugin); | |
| const rel = freshData.relations[id]; | |
| if (rel) { | |
| rel.publishedToGroupId = instance.publishedToGroupId; | |
| await saveRelations(plugin, freshData); | |
| } | |
| } | |
Was this helpful? React with 👍 or 👎 to provide feedback.
https://linear.app/discourse-graphs/issue/ENG-1300/publish-relations-when-a-node-is-published
https://www.loom.com/share/b7695fd01efb4e649848e4e362d17e91