Skip to content

feat: Workflow History V2 - eagerly load history#1123

Merged
adhityamamallan merged 10 commits intocadence-workflow:masterfrom
adhityamamallan:history-v2-eager-loading
Dec 22, 2025
Merged

feat: Workflow History V2 - eagerly load history#1123
adhityamamallan merged 10 commits intocadence-workflow:masterfrom
adhityamamallan:history-v2-eager-loading

Conversation

@adhityamamallan
Copy link
Member

@adhityamamallan adhityamamallan commented Dec 19, 2025

Summary

  • Modify WorkflowHistoryV2 to load the entire workflow history in all cases, instead of doing so conditionally
  • Use the throttle functionality implemented in feat: Implement optional throttling for fetching history pages in WorkflowHistoryFetcher #1122 to throttle calls to fetch history (1 per second) to avoid making calls in rapid succession for running workflows (observed when lots of activities are started after a wait)
  • Changes to useWorkflowHistoryFetcher to support passing fetchThrottleMs (also a bit of refactoring)
  • Copy WorkflowHistoryTableFooter from WorkflowHistoryTimelineLoadMore, removing the Intersection Observer logic that would load more history upon reaching the end

Test plan

Updated unit tests + ran locally.

Note: the errors in the bottom left are related to mismatches in SSR for the workflow status tag, and do not have anything to do with the current changes.

Loading a closed workflow

Screen.Recording.2025-12-19.at.16.54.40.mov

Loading a closed workflow, but one of the requests errors out and needs to be manually retried

Screen.Recording.2025-12-19.at.16.52.53.mov

Loading a running workflow

Screen.Recording.2025-12-19.at.16.55.43.mov

Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
@adhityamamallan adhityamamallan force-pushed the history-v2-eager-loading branch from 6407ce0 to 3fb506f Compare December 19, 2025 20:57
Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the Workflow History V2 component to eagerly load the entire workflow history instead of conditionally loading it. The key improvement is adding throttled fetch support to prevent rapid-fire API calls for running workflows while maintaining smooth UI updates through separate render throttling.

  • Introduces separate fetchThrottleMs (1s for running workflows) and renderThrottleMs (2s) configuration options
  • Creates a new reusable WorkflowHistoryTableFooter component to replace the old WorkflowHistoryTimelineLoadMore component
  • Simplifies the loading logic by removing complex conditional loading checks based on visible ranges and missing events

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/views/workflow-history/workflow-history.tsx Updated to use the new options object format for useWorkflowHistoryFetcher with onEventsChange and renderThrottleMs
src/views/workflow-history/hooks/use-workflow-history-fetcher.types.ts Added new types to support separate fetch and render throttling options
src/views/workflow-history/hooks/use-workflow-history-fetcher.ts Refactored to accept options object with fetchThrottleMs and renderThrottleMs, reorganized cleanup logic placement
src/views/workflow-history/hooks/__tests__/use-workflow-history-fetcher.test.tsx Updated tests to use new options object format
src/views/workflow-history/__tests__/workflow-history.test.tsx Updated mock to pass new options object format
src/views/workflow-history-v2/workflow-history-v2.tsx Major refactoring: removed conditional loading logic, added workflow state detection for throttling, simplified history fetching to eager loading
src/views/workflow-history-v2/workflow-history-ungrouped-table/workflow-history-ungrouped-table.tsx Updated to use new WorkflowHistoryTableFooter component with matching props
src/views/workflow-history-v2/workflow-history-ungrouped-table/__tests__/workflow-history-ungrouped-table.test.tsx Updated mock to match new footer component
src/views/workflow-history-v2/workflow-history-table-footer/workflow-history-table-footer.types.ts Added type definitions for the new footer component props
src/views/workflow-history-v2/workflow-history-table-footer/workflow-history-table-footer.tsx Created new footer component for loading states and error handling
src/views/workflow-history-v2/workflow-history-table-footer/workflow-history-table-footer.styles.ts Added styled components for the footer
src/views/workflow-history-v2/workflow-history-table-footer/__tests__/workflow-history-table-footer.test.tsx Added comprehensive tests for the new footer component
src/views/workflow-history-v2/workflow-history-grouped-table/workflow-history-grouped-table.tsx Updated to use new WorkflowHistoryTableFooter component with matching props
src/views/workflow-history-v2/workflow-history-grouped-table/__tests__/workflow-history-grouped-table.test.tsx Updated mock to match new footer component
src/views/workflow-history-v2/config/workflow-history-render-fetched-events-throttle-ms.config.ts Added new config for render throttling (2000ms)
src/views/workflow-history-v2/config/workflow-history-fetch-events-throttle-ms.config.ts Changed fetch throttle from 2000ms to 1000ms for running workflows
src/views/workflow-history-v2/__tests__/workflow-history-v2.test.tsx Updated tests to mock both throttle settings and use async queries where needed

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +8 to +36
describe(WorkflowHistoryTableFooter.name, () => {
it('renders loading spinner when hasMoreEvents is true', () => {
setup({ hasMoreEvents: true, isFetchingMoreEvents: false });

expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
});

it('renders loading spinner when isFetchingMoreEvents is true', () => {
setup({ hasMoreEvents: false, isFetchingMoreEvents: true });

expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
});

it('renders error message if there is an error, and allow retrying on click', () => {
const { mockFetchMoreEvents } = setup({
error: new RequestError('An error occurred', '/history', 500),
hasMoreEvents: false,
isFetchingMoreEvents: false,
});

expect(screen.getByText(/Failed to load more items./)).toBeInTheDocument();

act(() => {
fireEvent.click(screen.getByText(/Retry manually/));
});

expect(mockFetchMoreEvents).toHaveBeenCalled();
});
});
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test suite is missing a test case for when the component renders null (i.e., when error is null, hasMoreEvents is false, and isFetchingMoreEvents is false). Consider adding a test to verify this behavior to ensure complete test coverage.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice but testing this in our current setup doesn't quite work well because it renders two empty providers as opposed to null.

Comment on lines +85 to +88
const isWorkflowRunning =
!workflowExecutionInfo?.closeStatus ||
workflowExecutionInfo.closeStatus ===
'WORKFLOW_EXECUTION_CLOSE_STATUS_INVALID';
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isWorkflowRunning value should be memoized using useMemo to prevent unnecessary recalculations on every render. While the current implementation is functionally correct, memoizing this value would improve performance and make the dependency chain more predictable, especially since it affects the fetchThrottleMs value that is used in the startLoadingHistory callback.

Suggested change
const isWorkflowRunning =
!workflowExecutionInfo?.closeStatus ||
workflowExecutionInfo.closeStatus ===
'WORKFLOW_EXECUTION_CLOSE_STATUS_INVALID';
const isWorkflowRunning = useMemo(
() =>
!workflowExecutionInfo?.closeStatus ||
workflowExecutionInfo.closeStatus ===
'WORKFLOW_EXECUTION_CLOSE_STATUS_INVALID',
[workflowExecutionInfo?.closeStatus]
);

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a simple boolean expression, but it's likely that it will become more complex as we optimize the loading logic.

@adhityamamallan adhityamamallan merged commit ff5d39d into cadence-workflow:master Dec 22, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants