Implementation:TobikoData Sqlmesh Layout Worker Help
| Knowledge Sources | |
|---|---|
| Domains | Web_UI, Lineage_Visualization |
| Last Updated | 2026-02-07 20:00 GMT |
Overview
Web Worker management utilities for offloading graph layout calculations to background threads with timeout handling.
Description
Layout_Worker_Help provides functions for managing Web Workers that perform expensive graph layout calculations off the main thread. The module maintains a singleton worker instance through getWorker function and provides getLayoutedGraph async function that sends graph data to the worker and returns a Promise with positioned nodes. The worker communication includes timeout protection (default 1 minute), error handling for worker creation failures and post-message errors, and proper cleanup of event listeners. The cleanupLayoutWorker function terminates the worker and resets the singleton instance. This architecture prevents UI blocking during complex lineage graph layouts by leveraging browser Web Worker API.
Usage
Use these utilities when building lineage visualizations with large graphs that require layout calculation. The worker pattern keeps the UI responsive during expensive Dagre layout operations by running them in a background thread.
Code Reference
Source Location
- Repository: TobikoData_Sqlmesh
- File: web/common/src/components/Lineage/layout/help.ts
Signature
const DEFAULT_TIMEOUT = 1000 * 60 // 1 minute
export function getWorker(url: URL): Worker
export async function getLayoutedGraph<
TNodeData extends LineageNodeData = LineageNodeData,
TEdgeData extends LineageEdgeData = LineageEdgeData,
TEdgeID extends string = EdgeId,
TSourceID extends string = NodeId,
TTargetID extends string = NodeId,
TSourceHandleID extends string = PortId,
TTargetHandleID extends string = PortId,
>(
edges: LineageEdge<...>[],
nodesMap: LineageNodesMap<TNodeData>,
workerUrl: URL,
): Promise<LayoutedGraph<...>>
export function cleanupLayoutWorker(): void
Import
import {
getWorker,
getLayoutedGraph,
cleanupLayoutWorker,
} from '@sqlmesh-common/components/Lineage/layout/help'
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| url | URL | Yes (for getWorker) | URL to the worker script file |
| edges | LineageEdge[] | Yes (for getLayoutedGraph) | Array of graph edges |
| nodesMap | LineageNodesMap | Yes (for getLayoutedGraph) | Map of nodes by ID |
| workerUrl | URL | Yes (for getLayoutedGraph) | URL to the layout worker script |
Outputs
| Name | Type | Description |
|---|---|---|
| worker | Worker | Web Worker instance (singleton) |
| layoutedGraph | Promise<LayoutedGraph> | Promise resolving to positioned graph data |
| layoutedGraph.edges | LineageEdge[] | Original edges array |
| layoutedGraph.nodesMap | LineageNodesMap | Nodes map with calculated positions |
Usage Examples
import {
getLayoutedGraph,
cleanupLayoutWorker,
} from '@sqlmesh-common/components/Lineage/layout/help'
// Define worker URL (typically in public/ or assets/)
const workerUrl = new URL('/workers/layout.worker.js', import.meta.url)
async function calculateLineageLayout(edges, nodesMap) {
try {
// Offload layout calculation to Web Worker
const { edges: layoutedEdges, nodesMap: layoutedNodes } =
await getLayoutedGraph(edges, nodesMap, workerUrl)
console.log('Layout calculated in background thread')
return { edges: layoutedEdges, nodesMap: layoutedNodes }
} catch (error) {
console.error('Layout calculation failed:', error)
// Fallback to synchronous layout if worker fails
return calculateLayoutSync(edges, nodesMap)
}
}
// Component usage
function LineageGraph({ edges, nodesMap }) {
const [layoutedGraph, setLayoutedGraph] = useState(null)
const [isCalculating, setIsCalculating] = useState(true)
useEffect(() => {
calculateLineageLayout(edges, nodesMap)
.then(result => {
setLayoutedGraph(result)
setIsCalculating(false)
})
.catch(error => {
console.error('Failed to calculate layout:', error)
setIsCalculating(false)
})
// Cleanup on unmount
return () => {
cleanupLayoutWorker()
}
}, [edges, nodesMap])
if (isCalculating) {
return <LoadingSpinner message="Calculating layout..." />
}
return <ReactFlow nodes={layoutedGraph.nodesMap} edges={layoutedGraph.edges} />
}
// Timeout handling (1 minute default)
getLayoutedGraph(edges, nodesMap, workerUrl)
.catch(error => {
if (error.message === 'Layout calculation timed out') {
console.warn('Layout took too long, using fallback')
}
})