Skip to content

Commit 3df01e7

Browse files
chore(trigger): upsize task size (#6007)
* chore(trigger): upsize instances * chore(trigger): upsize tasks
1 parent bf376dd commit 3df01e7

7 files changed

Lines changed: 274 additions & 44 deletions

File tree

apps/sim/app/workspace/[workspaceId]/settings/components/activity-log/activity-log.tsx

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ const EVENT_COLUMN_WIDTH_CLASS = {
3232

3333
type EventColumnWidth = keyof typeof EVENT_COLUMN_WIDTH_CLASS
3434

35+
const ROW_CLASS = 'flex w-full items-center gap-3 px-3 py-2 text-left'
36+
3537
function ActivityLogRow({
3638
entry,
3739
eventColumn,
@@ -42,6 +44,39 @@ function ActivityLogRow({
4244
const [expanded, setExpanded] = useState(false)
4345
const expandable = entry.details != null
4446

47+
const cells = (
48+
<>
49+
<span className='w-[160px] flex-shrink-0 text-[var(--text-secondary)] text-small'>
50+
{entry.timestamp}
51+
</span>
52+
<span className={cn(EVENT_COLUMN_WIDTH_CLASS[eventColumn], 'flex-shrink-0')}>
53+
{entry.event}
54+
</span>
55+
<span className='min-w-0 flex-1 text-[var(--text-primary)] text-small'>
56+
{typeof entry.description === 'string' ? (
57+
<FloatingOverflowText label={entry.description} className='block truncate' />
58+
) : (
59+
entry.description
60+
)}
61+
</span>
62+
<span className='flex w-[160px] flex-shrink-0 items-center justify-end gap-1.5 text-[var(--text-secondary)] text-small'>
63+
{typeof entry.actor === 'string' ? (
64+
<FloatingOverflowText label={entry.actor} className='block min-w-0 truncate' />
65+
) : (
66+
<span className='min-w-0 truncate'>{entry.actor}</span>
67+
)}
68+
{expandable && (
69+
<ChevronDown
70+
className={cn(
71+
'size-[14px] flex-shrink-0 text-[var(--text-muted)] transition-transform duration-200',
72+
expanded && 'rotate-180'
73+
)}
74+
/>
75+
)}
76+
</span>
77+
</>
78+
)
79+
4580
return (
4681
<div
4782
className={cn(
@@ -50,42 +85,21 @@ function ActivityLogRow({
5085
expanded && 'bg-[var(--surface-2)]'
5186
)}
5287
>
53-
<button
54-
type='button'
55-
aria-expanded={expandable ? expanded : undefined}
56-
className='flex w-full items-center gap-3 px-3 py-2 text-left'
57-
onClick={() => expandable && setExpanded(!expanded)}
58-
disabled={!expandable}
59-
>
60-
<span className='w-[160px] flex-shrink-0 text-[var(--text-secondary)] text-small'>
61-
{entry.timestamp}
62-
</span>
63-
<span className={cn(EVENT_COLUMN_WIDTH_CLASS[eventColumn], 'flex-shrink-0')}>
64-
{entry.event}
65-
</span>
66-
<span className='min-w-0 flex-1 text-[var(--text-primary)] text-small'>
67-
{typeof entry.description === 'string' ? (
68-
<FloatingOverflowText label={entry.description} className='block truncate' />
69-
) : (
70-
entry.description
71-
)}
72-
</span>
73-
<span className='flex w-[160px] flex-shrink-0 items-center justify-end gap-1.5 text-[var(--text-secondary)] text-small'>
74-
{typeof entry.actor === 'string' ? (
75-
<FloatingOverflowText label={entry.actor} className='block min-w-0 truncate' />
76-
) : (
77-
<span className='min-w-0 truncate'>{entry.actor}</span>
78-
)}
79-
{expandable && (
80-
<ChevronDown
81-
className={cn(
82-
'size-[14px] flex-shrink-0 text-[var(--text-muted)] transition-transform duration-200',
83-
expanded && 'rotate-180'
84-
)}
85-
/>
86-
)}
87-
</span>
88-
</button>
88+
{expandable ? (
89+
<button
90+
type='button'
91+
aria-expanded={expanded}
92+
className={ROW_CLASS}
93+
onClick={() => setExpanded(!expanded)}
94+
>
95+
{cells}
96+
</button>
97+
) : (
98+
// A row with nothing to expand is inert content, not a disabled control:
99+
// browsers suppress pointer events over a disabled button AND its
100+
// descendants, which would swallow the hover tooltips inside the cells.
101+
<div className={ROW_CLASS}>{cells}</div>
102+
)}
89103
{expandable && expanded && (
90104
<div className='px-3 pb-2'>
91105
<div className='flex flex-col gap-1.5 rounded-lg border border-[var(--border-1)] bg-[var(--surface-3)] p-3 text-small'>

apps/sim/background/fork-content-copy.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,15 @@ import {
1111
* non-transactional best-effort (per-row inserts with fresh ids), so a blind
1212
* re-run would duplicate rows; a partial failure simply leaves the fork's content
1313
* incomplete (the workflows themselves committed synchronously).
14+
*
15+
* Runs on `large-2x` (8 vCPU / 16 GB), matching `knowledge-connector-sync`: the
16+
* copy materializes table rows, KB chunks and their embedding vectors, and file
17+
* blobs in memory, and `maxAttempts: 1` means an OOM is unrecoverable — a
18+
* half-copied fork with no retry.
1419
*/
1520
export const forkContentCopyTask = task({
1621
id: 'fork-content-copy',
22+
machine: 'large-2x',
1723
retry: { maxAttempts: 1 },
1824
queue: {
1925
name: 'fork-content-copy',

apps/sim/background/knowledge-connector-sync.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export async function executeConnectorSyncJob(payload: unknown) {
4040
export const knowledgeConnectorSync = task({
4141
id: 'knowledge-connector-sync',
4242
maxDuration: 1800,
43-
machine: 'large-1x',
43+
machine: 'large-2x',
4444
retry: {
4545
maxAttempts: 3,
4646
factor: 2,

apps/sim/background/schedule-execution.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1457,7 +1457,7 @@ export async function executeJobInline(payload: JobExecutionPayload) {
14571457

14581458
export const scheduleExecutionTaskOptions = {
14591459
id: 'schedule-execution',
1460-
machine: 'medium-1x' as const,
1460+
machine: 'medium-2x' as const,
14611461
retry: {
14621462
maxAttempts: 1,
14631463
},

apps/sim/background/workflow-execution.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ export async function executeWorkflowJob(payload: WorkflowExecutionPayload) {
230230

231231
export const workflowExecutionTask = task({
232232
id: 'workflow-execution',
233-
machine: 'medium-1x',
233+
machine: 'medium-2x',
234234
queue: {
235235
concurrencyLimit: WORKFLOW_EXECUTION_CONCURRENCY_LIMIT,
236236
},
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/**
2+
* @vitest-environment jsdom
3+
*/
4+
import { act } from 'react'
5+
import { createRoot, type Root } from 'react-dom/client'
6+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
7+
import type { BackgroundWorkItem } from '@/lib/api/contracts/workspace-fork'
8+
9+
const { mockUseWorkspaceBackgroundWork } = vi.hoisted(() => ({
10+
mockUseWorkspaceBackgroundWork: vi.fn(),
11+
}))
12+
13+
vi.mock('@/ee/workspace-forking/hooks/background-work', () => ({
14+
useWorkspaceBackgroundWork: mockUseWorkspaceBackgroundWork,
15+
}))
16+
17+
vi.mock('@/app/workspace/[workspaceId]/settings/components/settings-empty-state', () => ({
18+
SettingsEmptyState: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
19+
}))
20+
21+
vi.mock('@/app/workspace/[workspaceId]/components', () => ({
22+
FloatingOverflowText: ({ label, className }: { label: string; className?: string }) => (
23+
<span className={className}>{label}</span>
24+
),
25+
}))
26+
27+
import { ForkActivityPanel } from '@/ee/workspace-forking/components/fork-activity-panel/fork-activity-panel'
28+
29+
const WORKSPACE_ID = 'ws-1'
30+
const PARTNER_ID = 'ws-parent'
31+
const WORKSPACE_NAMES = new Map([[PARTNER_ID, 'another workspace']])
32+
33+
function makeJob(overrides: Partial<BackgroundWorkItem> = {}): BackgroundWorkItem {
34+
return {
35+
id: 'job-1',
36+
workspaceId: PARTNER_ID,
37+
workflowId: null,
38+
kind: 'fork_content_copy',
39+
status: 'completed',
40+
message: null,
41+
error: null,
42+
metadata: { childWorkspaceId: WORKSPACE_ID, actorName: 'Brandon Tarr' },
43+
startedAt: '2026-07-28T15:58:00.000Z',
44+
completedAt: null,
45+
...overrides,
46+
} as BackgroundWorkItem
47+
}
48+
49+
let container: HTMLDivElement
50+
let root: Root
51+
52+
function renderJobs(jobs: BackgroundWorkItem[]) {
53+
mockUseWorkspaceBackgroundWork.mockReturnValue({
54+
data: { pages: [{ items: jobs, nextCursor: null }] },
55+
isPending: false,
56+
isError: false,
57+
hasNextPage: false,
58+
fetchNextPage: vi.fn(),
59+
isFetchingNextPage: false,
60+
})
61+
act(() => {
62+
root.render(<ForkActivityPanel workspaceId={WORKSPACE_ID} workspaceNames={WORKSPACE_NAMES} />)
63+
})
64+
}
65+
66+
/** The Event-column badge for the single rendered row (`Badge`'s base class). */
67+
function badgeElement(): HTMLElement {
68+
const badge = container.querySelector<HTMLElement>('.inline-flex')
69+
if (!badge) throw new Error('badge not found')
70+
return badge
71+
}
72+
73+
/** Hover the badge the way React sees it — `onPointerEnter` is delegated from `pointerover`. */
74+
function hover(element: HTMLElement) {
75+
act(() => {
76+
element.dispatchEvent(
77+
new MouseEvent('pointerover', { bubbles: true, clientX: 100, clientY: 100 })
78+
)
79+
})
80+
}
81+
82+
function tooltipText(): string | null {
83+
return document.body.querySelector('[role="tooltip"]')?.textContent ?? null
84+
}
85+
86+
describe('ForkActivityPanel event badge tooltip', () => {
87+
beforeEach(() => {
88+
vi.clearAllMocks()
89+
container = document.createElement('div')
90+
document.body.appendChild(container)
91+
root = createRoot(container)
92+
})
93+
94+
afterEach(() => {
95+
act(() => root.unmount())
96+
container.remove()
97+
})
98+
99+
it('shows the failure reason when hovering a failed (red) badge', () => {
100+
renderJobs([makeJob({ status: 'failed', error: 'Storage quota exceeded while copying files' })])
101+
102+
expect(tooltipText()).toBeNull()
103+
hover(badgeElement())
104+
expect(tooltipText()).toBe('Storage quota exceeded while copying files')
105+
})
106+
107+
it('falls back to a generic label when a failed row carries no error text', () => {
108+
renderJobs([makeJob({ status: 'failed', error: null })])
109+
110+
hover(badgeElement())
111+
expect(tooltipText()).toBe('Failed')
112+
})
113+
114+
it('truncates a very long failure reason', () => {
115+
renderJobs([makeJob({ status: 'failed', error: 'x'.repeat(500) })])
116+
117+
hover(badgeElement())
118+
const text = tooltipText() ?? ''
119+
expect(text.endsWith('...')).toBe(true)
120+
expect(text.length).toBeLessThan(260)
121+
})
122+
123+
it('says "In progress" when hovering a processing (grey) badge', () => {
124+
renderJobs([makeJob({ status: 'processing' })])
125+
126+
hover(badgeElement())
127+
expect(tooltipText()).toBe('In progress')
128+
})
129+
130+
it('says "Queued" when hovering a pending (grey) badge', () => {
131+
renderJobs([makeJob({ status: 'pending' })])
132+
133+
hover(badgeElement())
134+
expect(tooltipText()).toBe('Queued')
135+
})
136+
137+
it('shows nothing when hovering a completed (blue) badge', () => {
138+
renderJobs([makeJob({ status: 'completed' })])
139+
140+
hover(badgeElement())
141+
expect(tooltipText()).toBeNull()
142+
})
143+
144+
it('surfaces the partial-copy summary on a completed_with_warnings (amber) badge', () => {
145+
renderJobs([
146+
makeJob({
147+
status: 'completed_with_warnings',
148+
message: 'Copied 12 items; 3 could not be copied',
149+
}),
150+
])
151+
152+
hover(badgeElement())
153+
expect(tooltipText()).toBe('Copied 12 items; 3 could not be copied')
154+
})
155+
156+
it('keeps a still-running row hoverable by not rendering it as a disabled button', () => {
157+
renderJobs([makeJob({ status: 'processing' })])
158+
159+
// A processing row has no report yet, so it is not expandable. It must still
160+
// be a plain row — a disabled button would swallow the badge's hover events.
161+
expect(container.querySelector('button[disabled]')).toBeNull()
162+
})
163+
164+
it('still renders an expandable row as a button', () => {
165+
renderJobs([makeJob({ status: 'failed', error: 'boom' })])
166+
167+
const row = container.querySelector('button')
168+
expect(row).not.toBeNull()
169+
expect(row?.getAttribute('aria-expanded')).toBe('false')
170+
})
171+
})

0 commit comments

Comments
 (0)