This is an automated email from the ASF dual-hosted git repository.
RocMarshal pushed a commit to branch release-2.3
in repository https://gitbox.apache.org/repos/asf/flink.git
The following commit(s) were added to refs/heads/release-2.3 by this push:
new 0e79fa52518 [FLINK-38900][runtime-web] Introduce the Rescales/Summary
sub-page for streaming jobs with the adaptive scheduler enabled (#27988)
0e79fa52518 is described below
commit 0e79fa52518300cf253885bf795af7aafd9fa09f
Author: Yuepeng Pan <[email protected]>
AuthorDate: Wed Apr 22 09:41:53 2026 +0800
[FLINK-38900][runtime-web] Introduce the Rescales/Summary sub-page for
streaming jobs with the adaptive scheduler enabled (#27988)
(cherry picked from commit fe8507c1eea5e2bf4cca4dc315e3fd8acaf187a0)
Co-authored-by: och5351 <[email protected]>
Co-authored-by: Matthias Pohl <[email protected]>
---
.../src/app/interfaces/job-rescales.ts | 25 ++
.../pages/job/rescales/job-rescales.component.html | 280 +++++++++++++++++++++
.../pages/job/rescales/job-rescales.component.ts | 22 +-
.../web-dashboard/src/app/services/job.service.ts | 5 +
4 files changed, 330 insertions(+), 2 deletions(-)
diff --git a/flink-runtime-web/web-dashboard/src/app/interfaces/job-rescales.ts
b/flink-runtime-web/web-dashboard/src/app/interfaces/job-rescales.ts
index 0cf7f521c36..2407d8cc819 100644
--- a/flink-runtime-web/web-dashboard/src/app/interfaces/job-rescales.ts
+++ b/flink-runtime-web/web-dashboard/src/app/interfaces/job-rescales.ts
@@ -21,6 +21,31 @@ export interface RescalesOverview {
latest: LatestRescales;
}
+export interface RescalesSummary {
+ rescalesCounts: RescalesCounts;
+ rescalesDurationStatsInMillis: RescalesDurationStatsInMillis;
+ completedRescalesDurationStatsInMillis:
DetailedRescalesDurationStatsInMillis;
+ ignoredRescalesDurationStatsInMillis: DetailedRescalesDurationStatsInMillis;
+ failedRescalesDurationStatsInMillis: DetailedRescalesDurationStatsInMillis;
+}
+
+export interface RescalesDurationStatsInMillis {
+ min: number;
+ max: number;
+ avg: number;
+}
+
+export interface DetailedRescalesDurationStatsInMillis {
+ min: number;
+ max: number;
+ avg: number;
+ p50: number | string;
+ p90: number | string;
+ p95: number | string;
+ p99: number | string;
+ p999: number | string;
+}
+
export interface RescalesCounts {
ignored: number;
inProgress: number;
diff --git
a/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.html
b/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.html
index 5bc5c64f5de..8f4a85d75c6 100644
---
a/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.html
+++
b/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.html
@@ -466,6 +466,286 @@
</tbody>
</nz-table>
</nz-tab>
+ <nz-tab nzTitle="Summary">
+ <nz-table
+ class="no-border small"
+ [nzData]="rescalesSummary ? [''] : []"
+ [nzSize]="'small'"
+ [nzFrontPagination]="false"
+ [nzShowPagination]="false"
+ >
+ <thead>
+ <tr>
+ <th><strong>Item</strong></th>
+ <th><strong>Stat</strong></th>
+ </tr>
+ </thead>
+ <tbody>
+ <ng-container *ngIf="rescalesSummary">
+ <tr>
+ <td>Total Rescales</td>
+ <td>{{ getTotalRescaleCountFromSummary() }}</td>
+ </tr>
+ <tr>
+ <td>In Progress Rescales</td>
+ <td>{{ rescalesSummary['rescalesCounts'].inProgress }}</td>
+ </tr>
+ <tr>
+ <td>Ignored Rescales</td>
+ <td>{{ rescalesSummary['rescalesCounts'].ignored }}</td>
+ </tr>
+ <tr>
+ <td>Completed Rescales</td>
+ <td>{{ rescalesSummary['rescalesCounts'].completed }}</td>
+ </tr>
+ <tr>
+ <td>Failed Rescales</td>
+ <td>{{ rescalesSummary['rescalesCounts'].failed }}</td>
+ </tr>
+ <tr>
+ <td>Rescale Duration Max</td>
+ <td>{{ rescalesSummary['rescalesDurationStatsInMillis'].max |
humanizeDuration }}</td>
+ </tr>
+ <tr>
+ <td>Rescale Duration Min</td>
+ <td>{{ rescalesSummary['rescalesDurationStatsInMillis'].min |
humanizeDuration }}</td>
+ </tr>
+ <tr>
+ <td>Rescale Duration Average</td>
+ <td>{{ rescalesSummary['rescalesDurationStatsInMillis'].avg |
humanizeDuration }}</td>
+ </tr>
+ </ng-container>
+ </tbody>
+ </nz-table>
+
+ <nz-collapse>
+ <nz-collapse-panel
+ [nzHeader]="'Rescale Duration Percentiles'"
+ [nzActive]="moreDetailsPanel.active"
+ [nzDisabled]="moreDetailsPanel.disabled"
+ >
+ <nz-table
+ *ngIf="rescalesSummary"
+ class="no-border small"
+ [nzData]="rescalesSummary ? [''] : []"
+ [nzSize]="'small'"
+ [nzFrontPagination]="false"
+ [nzShowPagination]="false"
+ >
+ <thead>
+ <tr>
+ <th></th>
+ <th><strong>Completed Rescale Duration</strong></th>
+ <th><strong>Ignored Rescale Duration</strong></th>
+ <th><strong>Failed Rescale Duration</strong></th>
+ </tr>
+ </thead>
+ <tbody>
+ <ng-container
+ *ngIf="
+ rescalesSummary['completedRescalesDurationStatsInMillis'] &&
+ rescalesSummary['ignoredRescalesDurationStatsInMillis'] &&
+ rescalesSummary['failedRescalesDurationStatsInMillis']
+ "
+ >
+ <tr>
+ <td><strong>Min</strong></td>
+ <td>
+ {{
+
rescalesSummary['completedRescalesDurationStatsInMillis']?.min
+ | humanizeDuration
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['ignoredRescalesDurationStatsInMillis']?.min | humanizeDuration
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['failedRescalesDurationStatsInMillis']?.min | humanizeDuration
+ }}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>Max</strong></td>
+ <td>
+ {{
+
rescalesSummary['completedRescalesDurationStatsInMillis']?.max
+ | humanizeDuration
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['ignoredRescalesDurationStatsInMillis']?.max | humanizeDuration
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['failedRescalesDurationStatsInMillis']?.max | humanizeDuration
+ }}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>Average</strong></td>
+ <td>
+ {{
+
rescalesSummary['completedRescalesDurationStatsInMillis']?.avg
+ | humanizeDuration
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['ignoredRescalesDurationStatsInMillis']?.avg | humanizeDuration
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['failedRescalesDurationStatsInMillis']?.avg | humanizeDuration
+ }}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>50% percentile</strong></td>
+ <td>
+ {{
+
rescalesSummary['completedRescalesDurationStatsInMillis']?.p50 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['completedRescalesDurationStatsInMillis']?.p50
+ | humanizeDuration)
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['ignoredRescalesDurationStatsInMillis']?.p50 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['ignoredRescalesDurationStatsInMillis']?.p50
+ | humanizeDuration)
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['failedRescalesDurationStatsInMillis']?.p50 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['failedRescalesDurationStatsInMillis']?.p50
+ | humanizeDuration)
+ }}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>90% percentile</strong></td>
+ <td>
+ {{
+
rescalesSummary['completedRescalesDurationStatsInMillis']?.p90 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['completedRescalesDurationStatsInMillis']?.p90
+ | humanizeDuration)
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['ignoredRescalesDurationStatsInMillis']?.p90 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['ignoredRescalesDurationStatsInMillis']?.p90
+ | humanizeDuration)
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['failedRescalesDurationStatsInMillis']?.p90 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['failedRescalesDurationStatsInMillis']?.p90
+ | humanizeDuration)
+ }}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>95% percentile</strong></td>
+ <td>
+ {{
+
rescalesSummary['completedRescalesDurationStatsInMillis']?.p95 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['completedRescalesDurationStatsInMillis']?.p95
+ | humanizeDuration)
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['ignoredRescalesDurationStatsInMillis']?.p95 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['ignoredRescalesDurationStatsInMillis']?.p95
+ | humanizeDuration)
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['failedRescalesDurationStatsInMillis']?.p95 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['failedRescalesDurationStatsInMillis']?.p95
+ | humanizeDuration)
+ }}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>99% percentile</strong></td>
+ <td>
+ {{
+
rescalesSummary['completedRescalesDurationStatsInMillis']?.p99 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['completedRescalesDurationStatsInMillis']?.p99
+ | humanizeDuration)
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['ignoredRescalesDurationStatsInMillis']?.p99 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['ignoredRescalesDurationStatsInMillis']?.p99
+ | humanizeDuration)
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['failedRescalesDurationStatsInMillis']?.p99 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['failedRescalesDurationStatsInMillis']?.p99
+ | humanizeDuration)
+ }}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>99.9% percentile</strong></td>
+ <td>
+ {{
+
rescalesSummary['completedRescalesDurationStatsInMillis']?.p999 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['completedRescalesDurationStatsInMillis']?.p999
+ | humanizeDuration)
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['ignoredRescalesDurationStatsInMillis']?.p999 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['ignoredRescalesDurationStatsInMillis']?.p999
+ | humanizeDuration)
+ }}
+ </td>
+ <td>
+ {{
+
rescalesSummary['failedRescalesDurationStatsInMillis']?.p999 === 'NaN'
+ ? 'n/a'
+ :
(rescalesSummary['failedRescalesDurationStatsInMillis']?.p999
+ | humanizeDuration)
+ }}
+ </td>
+ </tr>
+ </ng-container>
+ </tbody>
+ </nz-table>
+ </nz-collapse-panel>
+ </nz-collapse>
+ </nz-tab>
<nz-tab nzTitle="Configuration">
<nz-table
class="no-border small"
diff --git
a/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.ts
b/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.ts
index e25d8747d44..977b5de36dd 100644
---
a/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.ts
+++
b/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.ts
@@ -29,7 +29,8 @@ import {
JobRescaleConfigInfo,
JobDetail,
RescalesHistory,
- RescalesOverview
+ RescalesOverview,
+ RescalesSummary
} from '@flink-runtime-web/interfaces';
import { JobService } from '@flink-runtime-web/services';
import { NzButtonModule } from 'ng-zorro-antd/button';
@@ -69,6 +70,7 @@ import { JobLocalService } from '../job-local.service';
})
export class JobRescalesComponent implements OnInit, OnDestroy {
public rescalesOverview?: RescalesOverview;
+ public rescalesSummary?: RescalesSummary;
public rescalesHistory?: RescalesHistory;
public rescaleDetailsMap = new Map<string, JobRescaleDetails>();
public rescalesConfig?: JobRescaleConfigInfo;
@@ -95,6 +97,11 @@ export class JobRescalesComponent implements OnInit,
OnDestroy {
return of(undefined);
})
),
+ this.jobService.loadRescalesSummary(this.jobDetail.jid).pipe(
+ catchError(() => {
+ return of(undefined);
+ })
+ ),
this.jobService.loadRescalesHistory(this.jobDetail.jid).pipe(
catchError(() => {
return of(undefined);
@@ -109,8 +116,9 @@ export class JobRescalesComponent implements OnInit,
OnDestroy {
),
takeUntil(this.destroy$)
)
- .subscribe(([overview, history, config]) => {
+ .subscribe(([overview, summary, history, config]) => {
this.rescalesOverview = overview;
+ this.rescalesSummary = summary;
this.rescalesHistory = history;
this.rescalesConfig = config;
@@ -149,6 +157,8 @@ export class JobRescalesComponent implements OnInit,
OnDestroy {
this.refresh$.complete();
}
+ public moreDetailsPanel = { active: false, disabled: false };
+
public refresh(): void {
const expandedUuids = Array.from(this.expandedRowsSet);
@@ -210,6 +220,14 @@ export class JobRescalesComponent implements OnInit,
OnDestroy {
return counts.inProgress + counts.completed + counts.failed +
counts.ignored;
}
+ public getTotalRescaleCountFromSummary(): number {
+ if (!this.rescalesSummary?.rescalesCounts) {
+ return 0;
+ }
+ const counts = this.rescalesSummary.rescalesCounts;
+ return counts.inProgress + counts.completed + counts.failed +
counts.ignored;
+ }
+
private loadRescaleDetailIfNeeded(rescaleUuid: string): void {
if (!this.rescaleDetailsMap.has(rescaleUuid)) {
this.jobService
diff --git a/flink-runtime-web/web-dashboard/src/app/services/job.service.ts
b/flink-runtime-web/web-dashboard/src/app/services/job.service.ts
index a5bb8252e0b..4bcabff12ac 100644
--- a/flink-runtime-web/web-dashboard/src/app/services/job.service.ts
+++ b/flink-runtime-web/web-dashboard/src/app/services/job.service.ts
@@ -27,6 +27,7 @@ import {
CheckpointDetail,
CheckpointSubTask,
RescalesOverview,
+ RescalesSummary,
RescalesHistory,
JobRescaleDetails,
JobRescaleConfigInfo,
@@ -186,6 +187,10 @@ export class JobService {
return
this.httpClient.get<RescalesOverview>(`${this.configService.BASE_URL}/jobs/${jobId}/rescales/overview`);
}
+ public loadRescalesSummary(jobId: string): Observable<RescalesSummary> {
+ return
this.httpClient.get<RescalesSummary>(`${this.configService.BASE_URL}/jobs/${jobId}/rescales/summary`);
+ }
+
public loadRescalesHistory(jobId: string): Observable<RescalesHistory> {
return
this.httpClient.get<RescalesHistory>(`${this.configService.BASE_URL}/jobs/${jobId}/rescales/history`);
}