You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by uc...@apache.org on 2017/01/10 08:49:47 UTC
[08/11] flink git commit: [FLINK-4410] [runtime-web] Add new layout
for checkpoint stats
[FLINK-4410] [runtime-web] Add new layout for checkpoint stats
Project: http://git-wip-us.apache.org/repos/asf/flink/repo
Commit: http://git-wip-us.apache.org/repos/asf/flink/commit/27df8011
Tree: http://git-wip-us.apache.org/repos/asf/flink/tree/27df8011
Diff: http://git-wip-us.apache.org/repos/asf/flink/diff/27df8011
Branch: refs/heads/master
Commit: 27df8011125d486a055937a3e1e224e98b6add2f
Parents: dec0d6b
Author: Ufuk Celebi <uc...@apache.org>
Authored: Fri Dec 23 20:44:59 2016 +0100
Committer: Ufuk Celebi <uc...@apache.org>
Committed: Tue Jan 10 09:48:52 2017 +0100
----------------------------------------------------------------------
.../jobs/job.plan.node-list.checkpoints.jade | 38 ++---
.../jobs/job.plan.node.checkpoints.config.jade | 49 ++++++
.../jobs/job.plan.node.checkpoints.details.jade | 156 +++++++++++++++++++
.../jobs/job.plan.node.checkpoints.history.jade | 61 ++++++++
.../job.plan.node.checkpoints.overview.jade | 69 ++++++++
.../jobs/job.plan.node.checkpoints.summary.jade | 44 ++++++
.../app/scripts/common/filters.coffee | 3 +
.../web-dashboard/app/scripts/index.coffee | 36 +++++
.../app/scripts/modules/jobs/jobs.ctrl.coffee | 70 ++++++---
.../app/scripts/modules/jobs/jobs.svc.coffee | 62 +++++---
.../web-dashboard/app/styles/job.styl | 19 +++
11 files changed, 543 insertions(+), 64 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.checkpoints.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.checkpoints.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.checkpoints.jade
index 229d878..5db3d28 100644
--- a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.checkpoints.jade
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.checkpoints.jade
@@ -15,29 +15,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-div(ng-if="!jobCheckpointStats")
- p
- em No checkpoints
+.split
+ nav.navbar.navbar-default.navbar-secondary-additional
+ ul.nav.nav-tabs
+ li(ui-sref-active='active')
+ a(ui-sref=".overview") Overview
+ li(ui-sref-active='active')
+ a(ui-sref=".history") History
+ li(ui-sref-active='active')
+ a(ui-sref=".summary") Summary
+ li(ui-sref-active='active')
+ a(ui-sref=".config") Configuration
+ li(ng-if="checkpointDetails.id != -1").active
+ a Details for Checkpoint {{ checkpointDetails.id }}
-div(ng-if="jobCheckpointStats")
- h2 Overview
+ .clean.checkpoints-view#checkpoints-view(ui-view="checkpoints-view")
- div(ng-include=" 'partials/jobs/job.plan.node.checkpoints.job.html' ")
-
- h2 Operators
-
- table.table.table-body-hover.table-clickable.table-activable
- thead
- tr
- th Name
- th Status
-
- tbody(ng-repeat="v in job.vertices" ng-class="{ active: v.id == nodeid }" ng-click="v.id == nodeid || changeNode(v.id)")
- tr(ng-if="v.type == 'regular'")
- td {{ v.name | humanizeText }}
- td
- bs-label(status="{{v.status}}") {{v.status}}
-
- tr(ng-if="nodeid && v.id == nodeid")
- td(colspan="10")
- div(ng-include=" 'partials/jobs/job.plan.node.checkpoints.operator.html' ")
http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.config.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.config.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.config.jade
new file mode 100644
index 0000000..4cd43f3
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.config.jade
@@ -0,0 +1,49 @@
+//
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+div(ng-if="checkpointConfig")
+ table.table
+ thead
+ tr
+ td #[strong Option]
+ td #[strong Value]
+ tbody
+ tr
+ td Checkpointing Mode
+ td(ng-if="checkpointConfig['mode'] == 'exactly_once'") Exactly Once
+ td(ng-if="checkpointConfig['mode'] != 'exactly_once'") At Least Once
+ tr
+ td Interval
+ td(ng-if="checkpointConfig['interval'] == '0x7fffffffffffffff'") Periodic checkpoints disabled
+ td(ng-if="checkpointConfig['interval'] != '0x7fffffffffffffff'") {{ checkpointConfig['interval'] | humanizeDuration }}
+ tr
+ td Timeout
+ td {{ checkpointConfig['timeout'] | humanizeDuration }}
+ tr
+ td Minimum Pause Between Checkpoints
+ td {{ checkpointConfig['min_pause'] | humanizeDuration }}
+ tr
+ td Maximum Concurrent Checkpoints
+ td {{ checkpointConfig['max_concurrent'] }}
+ tr
+ td Persist Checkpoints Externally
+ td(ng-if="checkpointConfig['externalization']['enabled']")
+ | Enabled
+ = ' '
+ span(ng-if="checkpointConfig['externalization']['delete_on_cancellation']") (delete on cancellation)
+ span(ng-if="!checkpointConfig['externalization']['delete_on_cancellation']") (retain on cancellation)
+ td(ng-if="!checkpointConfig['externalization']['enabled']") Disabled
http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.details.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.details.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.details.jade
new file mode 100644
index 0000000..e2b1038
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.details.jade
@@ -0,0 +1,156 @@
+//
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+div(ng-if="checkpoint")
+ table.table.table-inner
+ thead
+ tr
+ td #[strong ID]
+ td #[strong Status]
+ td #[strong Acknowledged]
+ td #[strong Trigger Time]
+ td #[strong Latest Acknowledgement]
+ td(ng-if="checkpoint['failure_timestamp']") #[strong Failure Time]
+ td #[strong End to End Duration]
+ td #[strong State Size]
+ td #[strong Buffered During Alignment]
+ td(ng-if="checkpoint['status'] == 'COMPLETED'") #[strong Discarded]
+ td(ng-if="checkpoint['external_path']") #[strong Path]
+ td(ng-if="checkpoint['failure_message']") #[strong Failure Message]
+ tbody
+ tr
+ td {{ checkpoint['id'] }}
+ td(ng-if="checkpoint['status'] == 'IN_PROGRESS'") #[i(aria-hidden="true").fa.fa-circle-o-notch.fa-spin.fa-fw] In progress #[i(ng-if="checkpoint['is_savepoint']") savepoint]
+ td(ng-if="checkpoint['status'] == 'COMPLETED'") #[i(aria-hidden="true").fa.fa-check] Completed #[i(ng-if="checkpoint['is_savepoint']") savepoint]
+ td(ng-if="checkpoint['status'] == 'FAILED'") #[i(aria-hidden="true").fa.fa-remove] Failed #[i(ng-if="checkpoint['is_savepoint']") savepoint]
+ td {{ checkpoint['num_acknowledged_subtasks'] }}/{{ checkpoint['num_subtasks'] }} ({{ checkpoint['num_acknowledged_subtasks']/checkpoint['num_subtasks'] | percentage }})
+ td {{ checkpoint['trigger_timestamp'] | amDateFormat:'H:mm:ss' }}
+ td(ng-if="checkpoint['latest_ack_timestamp'] >= 0") {{ checkpoint['latest_ack_timestamp'] | amDateFormat:'H:mm:ss' }}
+ td(ng-if="checkpoint['latest_ack_timestamp'] < 0") n/a
+ td(ng-if="checkpoint['failure_timestamp']") {{ checkpoint['failure_timestamp'] | amDateFormat:'H:mm:ss' }}
+ td(ng-if="checkpoint['end_to_end_duration'] >= 0") {{ checkpoint['end_to_end_duration'] | humanizeDuration }}
+ td(ng-if="heckpoint['end_to_end_duration'] < 0") n/a
+ td {{ checkpoint['state_size'] | humanizeBytes }}
+ td {{ checkpoint['alignment_buffered'] | humanizeBytes }}
+ td(ng-if="checkpoint['status'] == 'COMPLETED'") #[span(ng-if="checkpoint['discarded']") Yes]#[span(ng-if="!checkpoint['discarded']") No]
+ td(ng-if="checkpoint['external_path']") {{ checkpoint['external_path'] }}
+ td(ng-if="checkpoint['status'] == 'FAILED' && checkpoint['failure_message']") {{ checkpoint['failure_message'] }}
+ td(ng-if="checkpoint['status'] == 'FAILED' && !checkpoint['failure_message']") n/a
+
+ h4 Operators
+ table.table.table-body-hover.table-clickable.table-activable.subtask-details
+ thead
+ tr
+ td #[strong Name]
+ td #[strong Acknowleged]
+ td #[strong Latest Acknowledgment]
+ td #[strong End to End Duration]
+ td #[strong State Size]
+ td #[strong Buffered During Alignment]
+ td
+ tbody(ng-repeat="v in job.vertices" ng-class="{ active: v.id == nodeid }" ng-click="changeNode(v.id)")
+ tr(ng-if="v.type == 'regular'")
+ td {{ v.name | humanizeText }}
+ td {{ checkpoint['tasks'][v.id]['num_acknowledged_subtasks'] }}/{{ checkpoint['tasks'][v.id]['num_subtasks'] }} ({{ checkpoint['tasks'][v.id]['num_acknowledged_subtasks']/checkpoint['tasks'][v.id]['num_subtasks'] | percentage }})
+ td(ng-if="checkpoint['tasks'][v.id]['latest_ack_timestamp'] >= 0") {{ checkpoint['tasks'][v.id]['latest_ack_timestamp'] | amDateFormat:'H:mm:ss' }}
+ td(ng-if="checkpoint['tasks'][v.id]['latest_ack_timestamp'] < 0") n/a
+ td(ng-if="checkpoint['tasks'][v.id]['end_to_end_duration'] >= 0") {{ checkpoint['tasks'][v.id]['end_to_end_duration'] | humanizeDuration }}
+ td(ng-if="checkpoint['tasks'][v.id]['end_to_end_duration'] < 0") n/a
+ td {{ checkpoint['tasks'][v.id]['state_size'] | humanizeBytes }}
+ td {{ checkpoint['tasks'][v.id]['alignment_buffered'] | humanizeBytes }}
+ td
+ div(ng-if="!nodeid || v.id != nodeid")
+ a.btn.btn-default(ng-click="toggleFold()")
+ | Show Subtasks
+ = ' '
+ i.fa.fa-chevron-down
+ div(ng-if="nodeid && v.id == nodeid")
+ a.btn.btn-default(ng-click="toggleFold()")
+ | Hide Subtasks
+ = ' '
+ i.fa.fa-chevron-up
+ tr(ng-if="nodeid && v.id == nodeid")
+ td(colspan=7)
+ table.table.table-body-hover.table-inner.subtask-details
+ thead(ng-if="subtaskDetails[v.id]['summary']")
+ tr
+ td
+ td
+ td #[strong End to End Duration]
+ td #[strong State Size]
+ td #[strong Checkpoint Duration (Sync)]
+ td #[strong Checkpoint Duration (Async)]
+ td #[strong Alignment Buffered]
+ td #[strong Alignment Duration]
+ tr
+ td
+ td #[strong Minimum]
+ td {{ subtaskDetails[v.id]['summary']['end_to_end_duration']['min'] | humanizeDuration }}
+ td {{ subtaskDetails[v.id]['summary']['state_size']['min'] | humanizeBytes }}
+ td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['sync']['min'] | humanizeDuration }}
+ td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['async']['min'] | humanizeDuration }}
+ td {{ subtaskDetails[v.id]['summary']['alignment']['buffered']['min'] | humanizeBytes }}
+ td {{ subtaskDetails[v.id]['summary']['alignment']['duration']['min'] | humanizeDuration }}
+ tr
+ td
+ td #[strong Average]
+ td {{ subtaskDetails[v.id]['summary']['end_to_end_duration']['avg'] | humanizeDuration }}
+ td {{ subtaskDetails[v.id]['summary']['state_size']['avg'] | humanizeBytes }}
+ td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['sync']['avg'] | humanizeDuration }}
+ td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['async']['avg'] | humanizeDuration }}
+ td {{ subtaskDetails[v.id]['summary']['alignment']['buffered']['avg'] | humanizeBytes }}
+ td {{ subtaskDetails[v.id]['summary']['alignment']['duration']['avg'] | humanizeDuration }}
+ tr
+ td
+ td #[strong Maximum]
+ td {{ subtaskDetails[v.id]['summary']['end_to_end_duration']['max'] | humanizeDuration }}
+ td {{ subtaskDetails[v.id]['summary']['state_size']['max'] | humanizeBytes }}
+ td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['sync']['max'] | humanizeDuration }}
+ td {{ subtaskDetails[v.id]['summary']['checkpoint_duration']['async']['max'] | humanizeDuration }}
+ td {{ subtaskDetails[v.id]['summary']['alignment']['buffered']['max'] | humanizeBytes }}
+ td {{ subtaskDetails[v.id]['summary']['alignment']['duration']['max'] | humanizeDuration }}
+ tr.blank
+ td(colspan=8)
+ thead
+ tr
+ td #[strong Subtask #]
+ td #[strong Acknowledgement Time]
+ td #[strong End to End Duration]
+ td #[strong State Size]
+ td #[strong Checkpoint Duration (Sync)]
+ td #[strong Checkpoint Duration (Async)]
+ td #[strong Alignment Buffered]
+ td #[strong Alignment Duration]
+ tbody
+ tr(ng-repeat="subtask in subtaskDetails[v.id]['subtasks']")
+ td {{ subtask['index'] + 1 }}
+ td(ng-if-start="subtask['status'] == 'completed'") {{ subtask['ack_timestamp'] | amDateFormat:'H:mm:ss' }}
+ td {{ subtask['end_to_end_duration'] | humanizeDuration }}
+ td {{ subtask['state_size'] | humanizeBytes }}
+ td {{ subtask['checkpoint']['sync'] | humanizeDuration }}
+ td {{ subtask['checkpoint']['async'] | humanizeDuration }}
+ td {{ subtask['alignment']['buffered'] | humanizeBytes}}
+ td(ng-if-end) {{ subtask['alignment']['duration'] | humanizeDuration }}
+ td(ng-if="subtask['status'] == 'pending'" colspan=7) n/a
+
+div(ng-if="!checkpoint")
+ p(ng-if="unknown_checkpoint" role="alert").alert.alert-danger
+ strong Unknown or expired checkpoint ID.
+ p(ng-if="!unknown_checkpoint" role="alert").alert.alert-info
+ strong Waiting for response from JobManager with checkpoint details...
+ = ' '
+ i(aria-hidden="true").fa.fa-circle-o-notch.fa-spin.fa-fw
http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.history.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.history.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.history.jade
new file mode 100644
index 0000000..44cd3db
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.history.jade
@@ -0,0 +1,61 @@
+//
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+div(ng-if="checkpointStats['history'] && checkpointStats['history'].length > 0")
+ table.table
+ thead
+ tr
+ td #[strong ID]
+ td #[strong Status]
+ td #[strong Acknowledged]
+ td #[strong Trigger Time]
+ td #[strong Latest Acknowledgement]
+ td #[strong End to End Duration]
+ td #[strong State Size]
+ td #[strong Buffered During Alignment]
+ td
+ tbody
+ tr(ng-repeat="checkpoint in checkpointStats['history']" ng-class="{'bg-danger': checkpoint['status'] == 'FAILED'}")
+ td {{ checkpoint['id'] }}
+ td(ng-if="checkpoint['status'] == 'IN_PROGRESS'") #[i(aria-hidden="true").fa.fa-circle-o-notch.fa-spin.fa-fw] #[i(ng-if="checkpoint['is_savepoint']" aria-hidden="true").fa.fa-floppy-o]
+ td(ng-if="checkpoint['status'] == 'COMPLETED'") #[i(aria-hidden="true").fa.fa-check] #[i(ng-if="checkpoint['is_savepoint']" aria-hidden="true").fa.fa-floppy-o]
+ td(ng-if="checkpoint['status'] == 'FAILED'") #[i(aria-hidden="true").fa.fa-remove] #[i(ng-if="checkpoint['is_savepoint']" aria-hidden="true").fa.fa-floppy-o]
+ td {{ checkpoint['num_acknowledged_subtasks'] }}/{{ checkpoint['num_subtasks'] }}
+ = ' '
+ span(ng-if="checkpoint['status'] == 'IN_PROGRESS'") ({{ checkpoint['num_acknowledged_subtasks']/checkpoint['num_subtasks'] | percentage }})
+ td {{ checkpoint['trigger_timestamp'] | amDateFormat:'H:mm:ss' }}
+ td(ng-if="checkpoint['latest_ack_timestamp'] >= 0") {{ checkpoint['latest_ack_timestamp'] | amDateFormat:'H:mm:ss' }}
+ td(ng-if="checkpoint['latest_ack_timestamp'] < 0") n/a
+ td(ng-if="checkpoint['end_to_end_duration'] >= 0") {{ checkpoint['end_to_end_duration'] | humanizeDuration }}
+ td(ng-if="checkpoint['end_to_end_duration'] < 0") n/a
+ td {{ checkpoint['state_size'] | humanizeBytes }}
+ td {{ checkpoint['alignment_buffered'] | humanizeBytes }}
+ td
+ a.btn.btn-default(ui-sref="^.details({checkpointId: checkpoint['id']})")
+ i(aria-hidden="true").fa.fa-chevron-right
+ = ' '
+ strong More details
+ p
+ strong.small Status:
+ ul.small
+ li In Progress: #[i(aria-hidden="true").fa.fa-circle-o-notch.fa-spin.fa-fw]
+ li Completed: #[i(aria-hidden="true").fa.fa-check]
+ li Failed: #[i(aria-hidden="true").fa.fa-remove]
+ li Savepoint: #[i(aria-hidden="true").fa.fa-floppy-o]
+
+div(ng-if="checkpointStats['history'] && checkpointStats['history'].length == 0")
+ p(role="alert").alert.alert-info #[strong No checkpoint history available.]
http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.overview.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.overview.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.overview.jade
new file mode 100644
index 0000000..2a1af51
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.overview.jade
@@ -0,0 +1,69 @@
+//
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+div(ng-if="checkpointStats")
+ table.table.checkpoint-overview
+ thead
+ tr
+ td #[strong Checkpoint Counts]
+ td Triggered: {{ checkpointStats['counts']['total'] }}
+ span In Progress: {{ checkpointStats['counts']['in_progress'] }}
+ span Completed: {{ checkpointStats['counts']['completed'] }}
+ span Failed: {{ checkpointStats['counts']['failed'] }}
+ span Restored: {{ checkpointStats['counts']['restored'] }}
+ tr
+ td #[strong Latest Completed Checkpoint]
+ td(ng-if="checkpointStats['latest']['completed']") ID: {{ checkpointStats['latest']['completed']['id'] }}
+ span Completion Time: {{ checkpointStats['latest']['completed']['latest_ack_timestamp'] | amDateFormat:'H:mm:ss' }}
+ span End to End Duration: {{ checkpointStats['latest']['completed']['end_to_end_duration'] | humanizeDuration }}
+ span State Size: {{ checkpointStats['latest']['completed']['state_size'] | humanizeBytes }}
+ span
+ i(aria-hidden="true").fa.fa-caret-square-o-right
+ = ' '
+ a(ui-sref="^.details({checkpointId: checkpointStats['latest']['completed']['id']})") More details
+ td(ng-if="!checkpointStats['latest']['completed']") None
+ tr
+ td #[strong Latest Failed Checkpoint]
+ td(ng-if="checkpointStats['latest']['failed']")
+ | ID: {{ checkpointStats['latest']['failed']['id'] }}
+ span Failure Time: {{ checkpointStats['latest']['failed']['failure_timestamp'] | amDateFormat:'H:mm:ss' }}
+ span(ng-if="checkpointStats['latest']['failed']['failure_message']") Cause: {{ checkpointStats['latest']['failed']['failure_message'] }}
+ span(ng-if="!checkpointStats['latest']['failed']['failure_message']") Cause: n/a
+ span
+ i(aria-hidden="true").fa.fa-caret-square-o-right
+ = ' '
+ a(ui-sref="^.details({checkpointId: checkpointStats['latest']['failed']['id']})") More details
+ td(ng-if="!checkpointStats['latest']['failed']") None
+ tr
+ td #[strong Latest Savepoint]
+ td(ng-if="checkpointStats['latest']['savepoint']") ID: {{ checkpointStats['latest']['savepoint']['id'] }}
+ span Completion Time: {{ checkpointStats['latest']['savepoint']['latest_ack_timestamp'] | amDateFormat:'H:mm:ss' }}
+ span State Size: {{ checkpointStats['latest']['savepoint']['state_size'] | humanizeBytes }}
+ span Path: {{ checkpointStats['latest']['savepoint']['external_path'] }}
+ span
+ i(aria-hidden="true").fa.fa-caret-square-o-right
+ = ' '
+ a(ui-sref="^.details({checkpointId: checkpointStats['latest']['savepoint']['id']})") More details
+ td(ng-if="!checkpointStats['latest']['savepoint']") None
+ tr
+ td #[strong Latest Restore]
+ td(ng-if="checkpointStats['latest']['restored']") ID: {{ checkpointStats['latest']['restored']['id'] }}
+ span Restore Time: {{ checkpointStats['latest']['restored']['restore_timestamp'] | amDateFormat:'H:mm:ss' }}
+ span(ng-if="checkpointStats['latest']['restored']['is_savepoint']") Type: Savepoint
+ span(ng-if="!checkpointStats['latest']['restored']['is_savepoint']") Type: Checkpoint
+ span(ng-if="checkpointStats['latest']['restored']['external_path']") Path: {{ checkpointStats['latest']['restored']['external_path'] }}
+ td(ng-if="!checkpointStats['latest']['restored']") None
http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.summary.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.summary.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.summary.jade
new file mode 100644
index 0000000..503c243
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.checkpoints.summary.jade
@@ -0,0 +1,44 @@
+//
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+div(ng-if="checkpointStats['summary']")
+ table.table
+ thead
+ tr
+ td
+ td #[strong State Size]
+ td #[strong End to End Duration]
+ td #[strong Buffered During Alignment]
+ tbody
+ tr
+ td #[strong Minimum]
+ td {{ checkpointStats['summary']['end_to_end_duration']['min'] | humanizeDuration }}
+ td {{ checkpointStats['summary']['state_size']['min'] | humanizeBytes }}
+ td {{ checkpointStats['summary']['alignment_buffered']['min'] | humanizeBytes }}
+ tr
+ td #[strong Average]
+ td {{ checkpointStats['summary']['end_to_end_duration']['avg'] | humanizeDuration }}
+ td {{ checkpointStats['summary']['state_size']['avg'] | humanizeBytes }}
+ td {{ checkpointStats['summary']['alignment_buffered']['avg'] | humanizeBytes }}
+ tr
+ td #[strong Maximum]
+ td {{ checkpointStats['summary']['end_to_end_duration']['max'] | humanizeDuration }}
+ td {{ checkpointStats['summary']['state_size']['max'] | humanizeBytes }}
+ td {{ checkpointStats['summary']['alignment_buffered']['max'] | humanizeBytes }}
+ p These number are computed over #[i all] completed checkpoints.
+
+p(ng-if="!checkpointStats['summary']") No checkpoint statistics summary available.
http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee b/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
index c3030a9..e7e831c 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
@@ -78,3 +78,6 @@ angular.module('flinkApp')
.filter "toUpperCase", ->
(text) -> text.toUpperCase()
+
+.filter "percentage", ->
+ (number) -> (number * 100).toFixed(0) + '%'
http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/scripts/index.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/index.coffee b/flink-runtime-web/web-dashboard/app/scripts/index.coffee
index 98ce76a..95bb356 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/index.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/index.coffee
@@ -130,11 +130,47 @@ angular.module('flinkApp', ['ui.router', 'angularMoment', 'dndLists'])
.state "single-job.plan.checkpoints",
url: "/checkpoints"
+ redirectTo: "single-job.plan.checkpoints.overview"
views:
'node-details':
templateUrl: "partials/jobs/job.plan.node-list.checkpoints.html"
controller: 'JobPlanCheckpointsController'
+ .state "single-job.plan.checkpoints.overview",
+ url: "/overview"
+ views:
+ 'checkpoints-view':
+ templateUrl: "partials/jobs/job.plan.node.checkpoints.overview.html"
+ controller: 'JobPlanCheckpointsController'
+
+ .state "single-job.plan.checkpoints.summary",
+ url: "/summary"
+ views:
+ 'checkpoints-view':
+ templateUrl: "partials/jobs/job.plan.node.checkpoints.summary.html"
+ controller: 'JobPlanCheckpointsController'
+
+ .state "single-job.plan.checkpoints.history",
+ url: "/history"
+ views:
+ 'checkpoints-view':
+ templateUrl: "partials/jobs/job.plan.node.checkpoints.history.html"
+ controller: 'JobPlanCheckpointsController'
+
+ .state "single-job.plan.checkpoints.config",
+ url: "/config"
+ views:
+ 'checkpoints-view':
+ templateUrl: "partials/jobs/job.plan.node.checkpoints.config.html"
+ controller: 'JobPlanCheckpointsController'
+
+ .state "single-job.plan.checkpoints.details",
+ url: "/details/{checkpointId}"
+ views:
+ 'checkpoints-view':
+ templateUrl: "partials/jobs/job.plan.node.checkpoints.details.html"
+ controller: 'JobPlanCheckpointDetailsController'
+
.state "single-job.plan.backpressure",
url: "/backpressure"
views:
http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
index 2bcbc13..bbb57c5 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
@@ -47,8 +47,6 @@ angular.module('flinkApp')
$scope.job = null
$scope.plan = null
$scope.vertices = null
- $scope.jobCheckpointStats = null
- $scope.showHistory = false
$scope.backPressureOperatorStats = {}
JobsService.loadJob($stateParams.jobid).then (data) ->
@@ -69,7 +67,6 @@ angular.module('flinkApp')
$scope.job = null
$scope.plan = null
$scope.vertices = null
- $scope.jobCheckpointStats = null
$scope.backPressureOperatorStats = null
$interval.cancel(refresher)
@@ -84,9 +81,6 @@ angular.module('flinkApp')
JobsService.stopJob($stateParams.jobid).then (data) ->
{}
- $scope.toggleHistory = ->
- $scope.showHistory = !$scope.showHistory
-
# --------------------------------------
.controller 'JobPlanController', ($scope, $state, $stateParams, $window, JobsService) ->
@@ -166,26 +160,60 @@ angular.module('flinkApp')
# --------------------------------------
-.controller 'JobPlanCheckpointsController', ($scope, JobsService) ->
- getJobCheckpointStats = ->
- JobsService.getJobCheckpointStats($scope.jobid).then (data) ->
- $scope.jobCheckpointStats = data
+.controller 'JobPlanCheckpointsController', ($scope, $state, $stateParams, JobsService) ->
+ # Updated by the details handler for the sub checkpoints nav bar.
+ $scope.checkpointDetails = {}
+ $scope.checkpointDetails.id = -1
- getOperatorCheckpointStats = ->
- JobsService.getOperatorCheckpointStats($scope.nodeid).then (data) ->
- $scope.operatorCheckpointStats = data.operatorStats
- $scope.subtasksCheckpointStats = data.subtasksStats
+ # Request the config once (it's static)
+ JobsService.getCheckpointConfig().then (data) ->
+ $scope.checkpointConfig = data
- # Get the per job stats
- getJobCheckpointStats()
+ # General stats like counts, history, etc.
+ getGeneralCheckpointStats = ->
+ JobsService.getCheckpointStats().then (data) ->
+ if (data != null)
+ $scope.checkpointStats = data
- # Get the per operator stats
- if $scope.nodeid and (!$scope.vertex or !$scope.vertex.operatorCheckpointStats)
- getOperatorCheckpointStats()
+ # Trigger request
+ getGeneralCheckpointStats()
$scope.$on 'reload', (event) ->
- getJobCheckpointStats()
- getOperatorCheckpointStats() if $scope.nodeid
+ # Retrigger request
+ getGeneralCheckpointStats()
+
+# --------------------------------------
+
+.controller 'JobPlanCheckpointDetailsController', ($scope, $state, $stateParams, JobsService) ->
+ $scope.subtaskDetails = {}
+ $scope.checkpointDetails.id = $stateParams.checkpointId
+
+ # Detailed stats for a single checkpoint
+ getCheckpointDetails = (checkpointId) ->
+ JobsService.getCheckpointDetails(checkpointId).then (data) ->
+ if (data != null)
+ $scope.checkpoint = data
+ else
+ $scope.unknown_checkpoint = true
+
+ getCheckpointSubtaskDetails = (checkpointId, vertexId) ->
+ JobsService.getCheckpointSubtaskDetails(checkpointId, vertexId).then (data) ->
+ if (data != null)
+ $scope.subtaskDetails[vertexId] = data
+
+ getCheckpointDetails($stateParams.checkpointId)
+
+ if ($scope.nodeid)
+ getCheckpointSubtaskDetails($stateParams.checkpointId, $scope.nodeid)
+
+ $scope.$on 'reload', (event) ->
+ getCheckpointDetails($stateParams.checkpointId)
+
+ if ($scope.nodeid)
+ getCheckpointSubtaskDetails($stateParams.checkpointId, $scope.nodeid)
+
+ $scope.$on '$destroy', ->
+ $scope.checkpointDetails.id = -1
# --------------------------------------
http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.svc.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.svc.coffee b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.svc.coffee
index 71f0921..7351de8 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.svc.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.svc.coffee
@@ -199,7 +199,7 @@ angular.module('flinkApp')
deferreds.job.promise.then (data) =>
# vertex = @seekVertex(vertexid)
-
+ console.log(currentJob.jid)
$http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/vertices/" + vertexid + "/accumulators"
.success (data) ->
accumulators = data['user-accumulators']
@@ -212,37 +212,61 @@ angular.module('flinkApp')
deferred.promise
- # Job-level checkpoint stats
- @getJobCheckpointStats = (jobid) ->
+ # Checkpoint config
+ @getCheckpointConfig = ->
deferred = $q.defer()
- $http.get flinkConfig.jobServer + "jobs/" + jobid + "/checkpoints"
- .success (data, status, headers, config) =>
- if (angular.equals({}, data))
- deferred.resolve(deferred.resolve(null))
- else
- deferred.resolve(data)
+ deferreds.job.promise.then (data) =>
+ $http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/checkpoints/config"
+ .success (data) ->
+ if (angular.equals({}, data))
+ deferred.resolve(null)
+ else
+ deferred.resolve(data)
deferred.promise
- # Operator-level checkpoint stats
- @getOperatorCheckpointStats = (vertexid) ->
+ # General checkpoint stats like counts, history, etc.
+ @getCheckpointStats = ->
deferred = $q.defer()
deferreds.job.promise.then (data) =>
- $http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/vertices/" + vertexid + "/checkpoints"
+ $http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/checkpoints"
+ .success (data, status, headers, config) =>
+ if (angular.equals({}, data))
+ deferred.resolve(null)
+ else
+ deferred.resolve(data)
+
+ deferred.promise
+
+ # Detailed checkpoint stats for a single checkpoint
+ @getCheckpointDetails = (checkpointid) ->
+ deferred = $q.defer()
+
+ deferreds.job.promise.then (data) =>
+ $http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/checkpoints/details/" + checkpointid
.success (data) ->
# If no data available, we are done.
if (angular.equals({}, data))
- deferred.resolve({ operatorStats: null, subtasksStats: null })
+ deferred.resolve(null)
else
- operatorStats = { id: data['id'], timestamp: data['timestamp'], duration: data['duration'], size: data['size'] }
+ deferred.resolve(data)
+
+ deferred.promise
+
+ # Detailed subtask stats for a single checkpoint
+ @getCheckpointSubtaskDetails = (checkpointid, vertexid) ->
+ deferred = $q.defer()
- if (angular.equals({}, data['subtasks']))
- deferred.resolve({ operatorStats: operatorStats, subtasksStats: null })
- else
- subtaskStats = data['subtasks']
- deferred.resolve({ operatorStats: operatorStats, subtasksStats: subtaskStats })
+ deferreds.job.promise.then (data) =>
+ $http.get flinkConfig.jobServer + "jobs/" + currentJob.jid + "/checkpoints/details/" + checkpointid + "/subtasks/" + vertexid
+ .success (data) ->
+ # If no data available, we are done.
+ if (angular.equals({}, data))
+ deferred.resolve(null)
+ else
+ deferred.resolve(data)
deferred.promise
http://git-wip-us.apache.org/repos/asf/flink/blob/27df8011/flink-runtime-web/web-dashboard/app/styles/job.styl
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/styles/job.styl b/flink-runtime-web/web-dashboard/app/styles/job.styl
index e0b11fc..fc61d50 100644
--- a/flink-runtime-web/web-dashboard/app/styles/job.styl
+++ b/flink-runtime-web/web-dashboard/app/styles/job.styl
@@ -50,3 +50,22 @@
font-family: inherit
margin-top: -2px
+.checkpoints-view {
+ padding-top: 1em
+}
+
+.subtask-details {
+ .blank {
+ height: 2em
+ }
+}
+
+.checkpoint-overview {
+ td span {
+ padding-left: 2em
+ }
+
+ a {
+ color: black;
+ }
+}