Skip to content
This repository has been archived by the owner on Jul 8, 2021. It is now read-only.

Commit

Permalink
gui: further connect schedule changes
Browse files Browse the repository at this point in the history
Unify connection schedule for running and stopped suites, with maximum
update duration being PT15S. This is now OK for stopped suites because
the client will look for suite's `host:port` via contact file first, so
it should only hit the file system every 15S instead of the network.

Only display connect count down if the update duration is *at* the
maximum PT15S level. This is when a running suite that does not see much
update and when the suite has stopped.

Increase in update duration will now be a bit more gradual.
  • Loading branch information
matthewrmshin committed Oct 19, 2017
1 parent bf8de8d commit d6e396a
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 117 deletions.
32 changes: 14 additions & 18 deletions lib/cylc/gui/app_gcylc.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def __init__(self, host, theme, dot_size, filter_states_excl,
self.reconnect_duration_widget,
r"""Duration to next reconnect attempt
Use (Re-)connect button to reconnect immediately.""")
Use *Connect Now* button to reconnect immediately.""")

hbox = gtk.HBox(spacing=0)
self.pack_start(hbox, False, False)
Expand Down Expand Up @@ -430,7 +430,7 @@ def set_update_time(self, update_time_str, next_update_dt_str=None):
else:
gobject.idle_add(
self.reconnect_duration_widget.set_text,
" (reconnect in %s) " % next_update_dt_str)
" (next connect: %s) " % next_update_dt_str)

def _set_tooltip(self, widget, text):
tooltip = gtk.Tooltips()
Expand Down Expand Up @@ -1009,7 +1009,7 @@ def pause_suite(self, bt):
def resume_suite(self, bt):
"""Tell suite to release "held" status."""
self.put_comms_command('release_suite')
self.reset_connect(None)
self.reset_connect()

def stopsuite_default(self, *args):
"""Try to stop the suite (after currently running tasks...)."""
Expand Down Expand Up @@ -1196,7 +1196,7 @@ def startsuite(self, bt, window, coldstart_rb, warmstart_rb, restart_rb,
except OSError:
warning_dialog('Error: failed to start ' + self.cfg.suite,
self.window).warn()
self.reset_connect(None)
self.reset_connect()

def about(self, bt):
about = gtk.AboutDialog()
Expand Down Expand Up @@ -2456,15 +2456,15 @@ def create_main_menu(self):

self.view_menu.append(gtk.SeparatorMenuItem())

self.reset_connect_menuitem = gtk.ImageMenuItem("(_Re-)connect")
self.reset_connect_menuitem = gtk.ImageMenuItem("_Connect Now")
img = gtk.image_new_from_stock(gtk.STOCK_REFRESH, gtk.ICON_SIZE_MENU)
self.reset_connect_menuitem.set_image(img)
self._set_tooltip(
self.reset_connect_menuitem,
"""(Re-)connect to suite immediately.
"""Connect to suite immediately.
If gcylc is not connected to a running suite
it tries to reconnect after increasingly long delays,
If gcylc cannot connect to the suite,
it retries after increasingly long delays,
to reduce network traffic.""")
self.view_menu.append(self.reset_connect_menuitem)
self.reset_connect_menuitem.connect('activate', self.reset_connect)
Expand Down Expand Up @@ -3046,12 +3046,8 @@ def click_register(self, w):
self.reset(suite)

def reset_connect(self, _=None):
"""Force the polling schedule to go back to short intervals.
This is so that the GUI can immediately connect to the started suite.
"""
self.updater.next_update_time = time()
self.updater.connect_schd.stop()
"""Force a suite API call as soon as possible."""
self.updater.update_duration = self.updater.MIN_UPDATE_DURATION

def construct_command_menu(self, menu):
"""Constructs the top bar help menu in gcylc that lists all
Expand Down Expand Up @@ -3289,15 +3285,15 @@ def create_tool_bar(self):
self.reset_connect_toolbutton = gtk.ToolButton(
icon_widget=gtk.image_new_from_stock(
gtk.STOCK_REFRESH, gtk.ICON_SIZE_SMALL_TOOLBAR))
self.reset_connect_toolbutton.set_label("(Re-)connect")
self.reset_connect_toolbutton.set_label("Connect Now")
tooltip = gtk.Tooltips()
tooltip.enable()
tooltip.set_tip(
self.reset_connect_toolbutton,
"""(Re-)connect to suite immediately.
"""Connect to suite immediately.
If gcylc is not connected to a running suite
it tries to reconnect after increasingly long delays,
If gcylc cannot connect to the suite
it retries after increasingly long delays,
to reduce network traffic.""")
self.reset_connect_toolbutton.connect("clicked", self.reset_connect)
self.tool_bars[0].insert(self.reset_connect_toolbutton, 0)
Expand Down
124 changes: 25 additions & 99 deletions lib/cylc/gui/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,83 +39,8 @@
from cylc.version import CYLC_VERSION
from cylc.wallclock import (
get_current_time_string,
get_seconds_as_interval_string,
get_time_string_from_unix_time
)


class ConnectSchd(object):
"""Keep information on whether the updater should poll or not.
Attributes:
.t_init - start time
.t_prev - previous poll time
.dt_next - estimated duration before the next poll
"""

DELAYS = {
(None, 5.0): 1.0,
(5.0, 60.0): 5.0,
(60.0, 300.0): 60.0,
(300.0, None): 300.0}

def __init__(self, start=False):
"""Return a new instance.
If start is False, the updater can always poll.
If start is True, the updater should only poll if the ready method
returns True.
"""

self.t_init = None
self.t_prev = None
self.dt_next = 0.0
if start:
self.start()

def ready(self):
"""Return True if a poll is ready."""
self.dt_next = 0.0
if self.t_init is None:
return True
if self.t_prev is None:
self.t_prev = time()
return True
dt_init = time() - self.t_init
dt_prev = time() - self.t_prev
for key, delay in self.DELAYS.items():
lower, upper = key
if ((lower is None or dt_init >= lower) and
(upper is None or dt_init < upper)):
if dt_prev > delay:
self.t_prev = time()
return True
else:
self.dt_next = round(delay - dt_prev, 2)
if cylc.flags.debug:
print >> sys.stderr, (
' ConnectSchd not ready, next poll in PT%sS' %
self.dt_next)
return False
return True

def start(self):
"""Start keeping track of latest poll, if not already started."""
if self.t_init is None:
if cylc.flags.debug:
print >> sys.stderr, ' ConnectSchd start'
self.t_init = time()
self.t_prev = None

def stop(self):
"""Stop keeping track of latest poll."""
if self.t_init is not None or self.t_prev is not None:
if cylc.flags.debug:
print >> sys.stderr, ' ConnectSchd stop'
self.t_init = None
self.t_prev = None
get_seconds_as_interval_string as duration2str,
get_time_string_from_unix_time as time2str)


class Updater(threading.Thread):
Expand All @@ -124,6 +49,7 @@ class Updater(threading.Thread):

# Maximum and minute update durations (in seconds) for a running suite
MAX_UPDATE_DURATION = 15.0
MIN_UPDATE_DURATION = 1.0

def __init__(self, app):

Expand Down Expand Up @@ -153,12 +79,11 @@ def __init__(self, app):
self.mode = "waiting..."
self.update_time_str = "waiting..."
self.last_update_time = time()
self.next_update_time = self.last_update_time
self.update_duration = self.MIN_UPDATE_DURATION
self.status = SUITE_STATUS_NOT_CONNECTED
self.is_reloading = False
self.connected = False
self.no_update_event = threading.Event()
self.connect_schd = ConnectSchd()
self.ns_defn_order = []
self.dict_ns_defn_order = {}
self.restricted_display = app.restricted_display
Expand Down Expand Up @@ -189,7 +114,9 @@ def set_stopped(self):
self.full_mode = True
self.connected = False
self.set_status(SUITE_STATUS_STOPPED)
self.connect_schd.start()
self.update_duration += 1.0
if self.update_duration > self.MAX_UPDATE_DURATION:
self.update_duration = self.MAX_UPDATE_DURATION
self.state_summary = {}
self.full_state_summary = {}
self.fam_state_summary = {}
Expand Down Expand Up @@ -221,8 +148,7 @@ def set_stopped(self):
self.info_bar.set_stop_summary, stop_summary)
self.last_update_time = time()
try:
update_time_str = get_time_string_from_unix_time(
self.stop_summary[0]["last_updated"])
update_time_str = time2str(self.stop_summary[0]["last_updated"])
except (AttributeError, IndexError, KeyError, TypeError):
update_time_str = None
gobject.idle_add(
Expand Down Expand Up @@ -303,16 +229,18 @@ def stop(self):

def run(self):
"""Start the thread."""
prev_update_time = time()
while not self.quit:
now = time()
if self.no_update_event.is_set():
pass
elif not self.connect_schd.ready():
self.info_bar.set_update_time(
None,
get_seconds_as_interval_string(
round(self.connect_schd.dt_next)))
elif time() > self.next_update_time:
elif now > prev_update_time + self.update_duration:
self.update()
prev_update_time = time()
else:
duration = round(prev_update_time + self.update_duration - now)
if self.update_duration >= self.MAX_UPDATE_DURATION:
self.info_bar.set_update_time(None, duration2str(duration))
sleep(1)

def update(self):
Expand All @@ -329,6 +257,7 @@ def update(self):
if cylc.flags.debug:
sys.stderr.write("%s CONNECTED - suite cylc version=%s\n" % (
get_current_time_string(), gui_summary['cylc_version']))
self.info_bar.set_update_time(None, None)
if gui_summary['full_mode']:
gobject.idle_add(
self.app_window.set_title, "%s - %s:%s" % (
Expand All @@ -339,7 +268,6 @@ def update(self):
# This status will be very transient:
self.set_status(SUITE_STATUS_CONNECTED)

self.connect_schd.stop()
if gui_summary['cylc_version'] != CYLC_VERSION:
gobject.idle_add(self.warn, (
"Warning: cylc version mismatch!\n\n"
Expand Down Expand Up @@ -379,16 +307,15 @@ def update(self):
# more while the main loop is turning around events quickly, but less
# frequently during quiet time or when the main loop is busy.
if is_updated:
update_duration = 1.0
self.update_duration = self.MIN_UPDATE_DURATION
self.last_update_time = time()
else:
update_duration = time() - self.last_update_time
elif time() - self.last_update_time > self.update_duration:
self.update_duration += 1.0
if ('mean_main_loop_duration' in gui_summary and
gui_summary['mean_main_loop_duration'] > update_duration):
update_duration = gui_summary['mean_main_loop_duration']
if update_duration > self.MAX_UPDATE_DURATION:
update_duration = self.MAX_UPDATE_DURATION
self.next_update_time = time() + update_duration
gui_summary['mean_main_loop_duration'] > self.update_duration):
self.update_duration = gui_summary['mean_main_loop_duration']
if self.update_duration > self.MAX_UPDATE_DURATION:
self.update_duration = self.MAX_UPDATE_DURATION

def _update_err_log(self, gui_summary):
"""Update suite err log if necessary."""
Expand All @@ -409,8 +336,7 @@ def _update_state_summary(self, gui_summary):
self.ns_defn_order = nsdo
self.dict_ns_defn_order = dict(zip(nsdo, range(0, len(nsdo))))

self.update_time_str = get_time_string_from_unix_time(
glbl['last_updated'])
self.update_time_str = time2str(glbl['last_updated'])
self.global_summary = glbl

if self.restricted_display:
Expand Down
1 change: 1 addition & 0 deletions lib/cylc/gui/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ def get_id_summary(id_, task_state_summary, fam_state_summary, id_family_map):
return id_
return text


def get_logo():
"""Return the gcylc logo as a gtk.gdk.Pixbuf."""
logo_path = os.path.join(get_image_dir(), "logo.png")
Expand Down

0 comments on commit d6e396a

Please sign in to comment.