-
Notifications
You must be signed in to change notification settings - Fork 15
feat: add new tab to Node page with thread pool statistics #2599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
0f27a16
Initial plan
Copilot 91229e5
Add Threads tab to Node page with mock data and UI components
Copilot 905d732
Connect Threads component to API with mock data fallback
Copilot 9c04132
Final implementation: Complete Threads tab with documentation
Copilot 9734099
Add fields_required=-1 parameter to sysinfo API call for thread data
Copilot 62b163a
Remove mock data fallback from threads API - use only real backend data
Copilot 0020323
Fix duplicate API calls and use real backend data in threads tab
Copilot c13b1d0
fix: review fixes
Raubzeug 127d839
fix
Raubzeug File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
# Threads Tab Implementation Documentation | ||
|
||
## Overview | ||
|
||
This document describes the implementation of the Threads tab for the Node page in YDB Embedded UI, which displays detailed thread pool information as requested in issue #2051. | ||
|
||
## Features Implemented | ||
|
||
- **Complete UI Components**: Thread pools table with all required columns | ||
- **CPU Usage Visualization**: Progress bars showing system + user CPU usage with color coding | ||
- **Thread State Visualization**: Horizontal bar chart showing distribution of thread states (R, S, etc.) | ||
- **Real API Integration**: Connected to RTK Query with auto-refresh and error handling | ||
- **TypeScript Types**: Complete type definitions for thread pool information | ||
- **Internationalization**: Full i18n support following project conventions | ||
|
||
## Component Structure | ||
|
||
``` | ||
src/containers/Node/Threads/ | ||
├── Threads.tsx # Main component | ||
├── Threads.scss # Styling | ||
├── CpuUsageBar/ # CPU usage visualization | ||
│ ├── CpuUsageBar.tsx | ||
│ └── CpuUsageBar.scss | ||
├── ThreadStatesBar/ # Thread states visualization | ||
│ ├── ThreadStatesBar.tsx | ||
│ └── ThreadStatesBar.scss | ||
└── i18n/ # Internationalization | ||
├── en.json | ||
└── index.ts | ||
``` | ||
|
||
## Data Structure | ||
|
||
The component expects thread pool information in the following format: | ||
|
||
```typescript | ||
interface TThreadPoolInfo { | ||
Name?: string; // Thread pool name (e.g., "AwsEventLoop", "klktmr.IC") | ||
Threads?: number; // Number of threads in the pool | ||
SystemUsage?: number; // System CPU usage (0-1 range) | ||
UserUsage?: number; // User CPU usage (0-1 range) | ||
MinorPageFaults?: number; // Number of minor page faults | ||
MajorPageFaults?: number; // Number of major page faults | ||
States?: Record<string, number>; // Thread states with counts (e.g., {R: 2, S: 1}) | ||
} | ||
``` | ||
|
||
## Backend Integration Required | ||
|
||
Currently, the implementation uses mock data. To connect real data, the YDB backend needs to provide detailed thread information through one of these approaches: | ||
|
||
### Option 1: New Dedicated Endpoint (Recommended) | ||
|
||
``` | ||
GET /viewer/json/threads?node_id={nodeId} | ||
``` | ||
|
||
Response format: | ||
|
||
```json | ||
{ | ||
"Threads": [ | ||
{ | ||
"Name": "AwsEventLoop", | ||
"Threads": 64, | ||
"SystemUsage": 0.0, | ||
"UserUsage": 0.0, | ||
"MinorPageFaults": 0, | ||
"MajorPageFaults": 0, | ||
"States": { | ||
"S": 64 | ||
} | ||
} | ||
], | ||
"ResponseTime": "1234567890", | ||
"ResponseDuration": 123 | ||
} | ||
``` | ||
|
||
### Option 2: Extend Existing Endpoint | ||
|
||
Extend `/viewer/json/sysinfo` to include detailed thread information in addition to the current `PoolStats`. | ||
|
||
## API Implementation | ||
|
||
The frontend API integration is already implemented: | ||
|
||
1. **Viewer API**: `getNodeThreads()` method in `src/services/api/viewer.ts` | ||
2. **Node Store**: RTK Query endpoint in `src/store/reducers/node/node.ts` | ||
3. **Component**: Connected with auto-refresh in `src/containers/Node/Threads/Threads.tsx` | ||
|
||
## Data Mapping | ||
|
||
The backend should provide: | ||
|
||
- **Thread Pool Name**: From the actual thread pool name | ||
- **Thread Count**: Number of threads in each pool | ||
- **CPU Usage**: System and user CPU usage percentages (0-1 range) | ||
- **Page Faults**: Minor and major page fault counts | ||
- **Thread States**: Distribution of thread states using Linux process state codes: | ||
- `R`: Running | ||
- `S`: Sleeping (interruptible) | ||
- `D`: Disk sleep (uninterruptible) | ||
- `Z`: Zombie | ||
- `T`: Stopped | ||
- etc. | ||
|
||
## Screenshots | ||
|
||
The implementation provides a complete table view matching the requirements in the issue: | ||
|
||
- Pool name column | ||
- Thread count column | ||
- CPU usage with visual progress bar | ||
- Page fault counts | ||
- Thread state distribution visualization | ||
|
||
## Testing | ||
|
||
To test the implementation: | ||
|
||
1. Navigate to `/node/{nodeId}/threads` in the YDB Embedded UI | ||
2. The tab will be available in the node page tabs | ||
3. Currently shows mock data until backend integration is complete | ||
|
||
## Next Steps | ||
|
||
1. **Backend Development**: Implement the threads endpoint in YDB backend | ||
2. **Real Data Integration**: Replace mock data with actual thread information | ||
3. **Testing**: Verify with real YDB instances | ||
4. **Performance**: Ensure efficient data collection for thread statistics | ||
|
||
## Related Files | ||
|
||
- Node page tabs: `src/containers/Node/NodePages.ts` | ||
- Node page component: `src/containers/Node/Node.tsx` | ||
- Thread types: `src/types/api/threads.ts` | ||
- API viewer: `src/services/api/viewer.ts` | ||
- Node store: `src/store/reducers/node/node.ts` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
.cpu-usage-bar { | ||
display: flex; | ||
align-items: center; | ||
gap: 8px; | ||
|
||
min-width: 120px; | ||
|
||
&__progress { | ||
flex: 1; | ||
|
||
min-width: 60px; | ||
} | ||
|
||
&__text { | ||
font-size: 12px; | ||
white-space: nowrap; | ||
} | ||
|
||
&__total { | ||
font-weight: 500; | ||
} | ||
|
||
&__breakdown { | ||
margin-left: 4px; | ||
|
||
color: var(--g-color-text-secondary); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import {Progress} from '@gravity-ui/uikit'; | ||
|
||
import {cn} from '../../../../utils/cn'; | ||
|
||
import './CpuUsageBar.scss'; | ||
|
||
const b = cn('cpu-usage-bar'); | ||
|
||
interface CpuUsageBarProps { | ||
systemUsage?: number; | ||
userUsage?: number; | ||
className?: string; | ||
} | ||
|
||
/** | ||
* Component to display CPU usage as a progress bar showing both system and user usage | ||
*/ | ||
export function CpuUsageBar({systemUsage = 0, userUsage = 0, className}: CpuUsageBarProps) { | ||
const totalUsage = systemUsage + userUsage; | ||
const systemPercent = Math.round(systemUsage * 100); | ||
const userPercent = Math.round(userUsage * 100); | ||
const totalPercent = Math.round(totalUsage * 100); | ||
|
||
// Determine color based on total load | ||
const getProgressTheme = (): 'success' | 'warning' | 'danger' => { | ||
if (totalUsage >= 1.0) { | ||
return 'danger'; | ||
} // 100% or more load | ||
if (totalUsage >= 0.8) { | ||
return 'warning'; | ||
} // 80% or more load | ||
return 'success'; | ||
}; | ||
|
||
return ( | ||
<div className={b(null, className)}> | ||
<div className={b('progress')}> | ||
<Progress value={Math.min(totalPercent, 100)} theme={getProgressTheme()} size="s" /> | ||
</div> | ||
<div className={b('text')}> | ||
<span className={b('total')}>{totalPercent}%</span> | ||
<span className={b('breakdown')}> | ||
(S: {systemPercent}%, U: {userPercent}%) | ||
</span> | ||
</div> | ||
</div> | ||
); | ||
} |
49 changes: 49 additions & 0 deletions
49
src/containers/Node/Threads/ThreadStatesBar/ThreadStatesBar.scss
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
.thread-states-bar { | ||
&__bar { | ||
display: flex; | ||
overflow: hidden; | ||
|
||
min-width: 80px; | ||
height: 16px; | ||
margin-bottom: 4px; | ||
|
||
border: 1px solid var(--g-color-line-generic); | ||
border-radius: 4px; | ||
background-color: var(--g-color-base-generic); | ||
} | ||
|
||
&__segment { | ||
transition: opacity 0.2s ease; | ||
|
||
&:hover { | ||
opacity: 0.8; | ||
} | ||
} | ||
|
||
&__legend { | ||
display: flex; | ||
flex-wrap: wrap; | ||
gap: 8px; | ||
|
||
font-size: 11px; | ||
|
||
color: var(--g-color-text-secondary); | ||
} | ||
|
||
&__legend-item { | ||
display: flex; | ||
align-items: center; | ||
gap: 4px; | ||
|
||
white-space: nowrap; | ||
} | ||
|
||
&__legend-color { | ||
flex-shrink: 0; | ||
|
||
width: 8px; | ||
height: 8px; | ||
|
||
border-radius: 2px; | ||
} | ||
} |
76 changes: 76 additions & 0 deletions
76
src/containers/Node/Threads/ThreadStatesBar/ThreadStatesBar.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import {cn} from '../../../../utils/cn'; | ||
|
||
import './ThreadStatesBar.scss'; | ||
|
||
const b = cn('thread-states-bar'); | ||
|
||
interface ThreadStatesBarProps { | ||
states?: Record<string, number>; | ||
totalThreads?: number; | ||
className?: string; | ||
} | ||
|
||
/** | ||
* Thread state colors based on the state type | ||
*/ | ||
const getStateColor = (state: string): string => { | ||
switch (state.toUpperCase()) { | ||
case 'R': // Running | ||
return 'var(--g-color-text-positive)'; | ||
case 'S': // Sleeping | ||
return 'var(--g-color-text-secondary)'; | ||
case 'D': // Uninterruptible sleep | ||
return 'var(--g-color-text-warning)'; | ||
case 'Z': // Zombie | ||
case 'T': // Stopped | ||
case 'X': // Dead | ||
return 'var(--g-color-text-danger)'; | ||
default: | ||
return 'var(--g-color-text-misc)'; | ||
} | ||
}; | ||
|
||
/** | ||
* Component to display thread states as a horizontal bar chart | ||
*/ | ||
export function ThreadStatesBar({states = {}, totalThreads, className}: ThreadStatesBarProps) { | ||
const total = totalThreads || Object.values(states).reduce((sum, count) => sum + count, 0); | ||
|
||
if (total === 0) { | ||
return <div className={b(null, className)}>No threads</div>; | ||
} | ||
|
||
const stateEntries = Object.entries(states).filter(([, count]) => count > 0); | ||
|
||
return ( | ||
<div className={b(null, className)}> | ||
<div className={b('bar')}> | ||
{stateEntries.map(([state, count]) => { | ||
const percentage = (count / total) * 100; | ||
return ( | ||
<div | ||
key={state} | ||
className={b('segment')} | ||
style={{ | ||
width: `${percentage}%`, | ||
backgroundColor: getStateColor(state), | ||
}} | ||
title={`${state}: ${count} threads (${Math.round(percentage)}%)`} | ||
/> | ||
); | ||
})} | ||
</div> | ||
<div className={b('legend')}> | ||
{stateEntries.map(([state, count]) => ( | ||
<span key={state} className={b('legend-item')}> | ||
<span | ||
className={b('legend-color')} | ||
style={{backgroundColor: getStateColor(state)}} | ||
/> | ||
{state}: {count} | ||
</span> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The magic numbers 1.0 and 0.8 should be extracted as named constants to improve maintainability and make the thresholds configurable.
Copilot uses AI. Check for mistakes.