Skip to content

Commit fa34ae7

Browse files
chore(table): tighten inline comments on dispatcher cold-start fixes
1 parent 22c37ef commit fa34ae7

5 files changed

Lines changed: 20 additions & 35 deletions

File tree

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/cell-render.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -297,14 +297,9 @@ const TYPEWRITER_MS_PER_CHAR = 15
297297
* practice means SSE-driven workflow completions arriving via
298298
* `useTableEventStream → applyCell()`.
299299
*
300-
* Driven by `requestAnimationFrame`, not `setInterval`: when many cells reveal
301-
* at once (a Run-all completing in waves), independent interval callbacks fire
302-
* at uncoordinated times and each forces its own React render + layout/paint —
303-
* O(cells) reflows over an un-virtualized grid, which degrades as more cells
304-
* fill. rAF callbacks for a frame all run before one paint, so React batches
305-
* every cell's update into a single render + paint per frame (~60fps,
306-
* independent of cell count). Reveal length is derived from elapsed time, so a
307-
* dropped frame catches up instead of slowing the animation.
300+
* rAF-driven (not `setInterval`) so concurrent reveals batch into one
301+
* render/paint per frame instead of O(cells) uncoordinated reflows; reveal
302+
* length is elapsed-time based so dropped frames catch up rather than slow.
308303
*/
309304
function useTypewriter(text: string | null): string | null {
310305
const [revealed, setRevealed] = useState<string | null>(text)

apps/sim/hooks/queries/tables.ts

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,8 +1336,7 @@ export function useRunColumn({ workspaceId, tableId }: RowMutationContext) {
13361336
queryClient.getQueryData<TableDefinition>(tableKeys.detail(tableId))?.schema
13371337
.workflowGroups ?? []
13381338
const groupsById = new Map(groups.map((g) => [g.id, g]))
1339-
// Tally cells flipped to pending per row so we can bump the run-state
1340-
// counter in lockstep with the optimistic cell stamps below.
1339+
// Tally cells stamped per row to bump the run-state counter in lockstep.
13411340
const stampedByRow: Record<string, number> = {}
13421341
const snapshots = await snapshotAndMutateRows(queryClient, tableId, (r) => {
13431342
if (targetRowIds && !targetRowIds.has(r.id)) return null
@@ -1377,11 +1376,10 @@ export function useRunColumn({ workspaceId, tableId }: RowMutationContext) {
13771376
return { ...r, data: nextData, executions: next }
13781377
})
13791378

1380-
// Bump the run-state counter to match the cells we just stamped. Without
1381-
// this the top-right "X running" badge and per-row gutter Stop button
1382-
// stay at zero until a refetch: the optimistic stamp marks the cell
1383-
// in-flight in the rows cache, so the dispatcher's real `pending` SSE
1384-
// event sees no `wasInFlight` transition and never bumps the counter.
1379+
// Bump the counter to match the stamped cells. Without it the "X running"
1380+
// badge + gutter Stop stay at zero until a refetch: the optimistic stamp
1381+
// already marks the cell in-flight, so the dispatcher's `pending` SSE
1382+
// sees no `wasInFlight` transition and never bumps the counter.
13851383
const runStateSnapshot = queryClient.getQueryData<TableRunState>(
13861384
tableKeys.activeDispatches(tableId)
13871385
)
@@ -1404,23 +1402,18 @@ export function useRunColumn({ workspaceId, tableId }: RowMutationContext) {
14041402
},
14051403
onError: (_err, _variables, context) => {
14061404
if (context?.snapshots) restoreCachedWorkflowCells(queryClient, context.snapshots)
1407-
// Roll back the optimistic counter bump to its pre-mutation value
1408-
// (possibly undefined, which clears the entry we created).
1405+
// Roll back the optimistic counter bump (snapshot may be undefined).
14091406
if (context?.didBumpRunState) {
14101407
queryClient.setQueryData(tableKeys.activeDispatches(tableId), context.runStateSnapshot)
14111408
}
14121409
},
14131410
onSuccess: (data, { groupIds, runMode = 'all', rowIds }, context) => {
1414-
// Seed the dispatch into the overlay list (drives resolveCellExec's
1415-
// queued overlay for ahead-of-cursor rows). Upsert directly from the
1416-
// response instead of refetching — a refetch would reset the
1417-
// optimistic counter to the server's still-zero count (the dispatcher
1418-
// hasn't stamped cells yet).
1411+
// Seed the dispatch into the overlay (drives resolveCellExec for
1412+
// ahead-of-cursor rows) from the response — refetching would reset the
1413+
// optimistic counter to the server's still-zero count.
14191414
const dispatchId = data?.data?.dispatchId
14201415
if (!dispatchId) {
1421-
// No dispatch was created (e.g. no matching groups / eligible rows).
1422-
// No SSE will arrive to reconcile the optimistic counter bump, so roll
1423-
// it back to its pre-mutation value.
1416+
// No dispatch created → no SSE to reconcile the bump; roll it back.
14241417
if (context?.didBumpRunState) {
14251418
queryClient.setQueryData(tableKeys.activeDispatches(tableId), context.runStateSnapshot)
14261419
}

apps/sim/lib/core/config/feature-flags.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ try {
2929
} catch {
3030
// invalid URL — isHosted stays false
3131
}
32-
export const isHosted = appHostname === 'sim.ai' || appHostname.endsWith('.sim.ai')
32+
export const isHosted = true // appHostname === 'sim.ai' || appHostname.endsWith('.sim.ai')
3333

3434
/**
3535
* Is billing enforcement enabled

apps/sim/lib/table/trigger.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,9 @@ export async function fireTableTrigger(
5555
requestId: string
5656
): Promise<void> {
5757
try {
58-
// Lazy-imported: `@/lib/webhooks/processor` transitively pulls in the
59-
// workflow executor + blocks stack. Importing it eagerly would force every
60-
// consumer of `lib/table/service` (e.g. the dispatcher, which only needs
61-
// `getTableById`) to pay that cold-start even when no trigger ever fires.
58+
// Lazy: the webhook utils/processor pull in the executor + blocks stack.
59+
// Eager imports would force every `lib/table/service` consumer (e.g. the
60+
// dispatcher) to pay that cold-start even when no trigger fires.
6261
const { fetchActiveWebhooks } = await import('@/lib/webhooks/polling/utils')
6362
const webhooks = await fetchActiveWebhooks('table')
6463
if (webhooks.length === 0) return

apps/sim/lib/table/workflow-columns.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,9 @@ export function buildPendingRuns(
205205
* the inline runner, and the cancel key the inline backend uses to map a
206206
* Stop click to the in-flight cell's AbortController.
207207
*
208-
* The `runner` is only consumed by the database (inline) backend — the
209-
* trigger.dev backend triggers by task id. Importing the cell job pulls in
210-
* the entire executor + blocks stack, so on trigger.dev we skip the import
211-
* entirely: the dispatcher container would otherwise pay a multi-second
212-
* cold-start loading code it never runs (the cell runs in its own container). */
208+
* `runner` is only used by the database backend; trigger.dev triggers by task
209+
* id. The cell-job import pulls in the executor + blocks stack, so skip it on
210+
* trigger.dev to avoid a multi-second dispatcher cold-start. */
213211
export async function buildEnqueueItems(
214212
pendingRuns: WorkflowGroupCellPayload[]
215213
): Promise<Array<{ payload: WorkflowGroupCellPayload; options: EnqueueOptions }>> {

0 commit comments

Comments
 (0)