Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Features
* Make the completion interface more responsive using a background thread.
* Option to suppress control-d exit behavior.
* Better support Truecolor terminals.
* Ability to send app-layer keepalive pings to the server.


Bug Fixes
Expand Down
31 changes: 29 additions & 2 deletions mycli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ def __init__(
self.login_path = login_path
self.toolbar_error_message: str | None = None
self.prompt_app: PromptSession | None = None
self._keepalive_counter = 0

# self.cnf_files is a class variable that stores the list of mysql
# config files to read in at launch.
Expand All @@ -185,6 +186,7 @@ def __init__(
special.set_timing_enabled(c["main"].as_bool("timing"))
special.set_show_favorite_query(c["main"].as_bool("show_favorite_query"))
self.beep_after_seconds = float(c["main"]["beep_after_seconds"] or 0)
self.default_keepalive_ticks = c['connection'].as_int('default_keepalive_ticks')

FavoriteQueries.instance = FavoriteQueries.from_config(self.config)

Expand Down Expand Up @@ -782,6 +784,7 @@ def handle_editor_command(self, text: str) -> str:
while True:
try:
assert isinstance(self.prompt_app, PromptSession)
# buglet: this prompt() invocation doesn't have an inputhook for keepalive pings
text = self.prompt_app.prompt(default=sql)
break
except KeyboardInterrupt:
Expand Down Expand Up @@ -986,11 +989,35 @@ def output_res(results: Generator[SQLResult], start: float) -> None:
self.echo("")
self.output(formatted, status)

def keepalive_hook(_context):
"""
prompt_toolkit shares the event loop with this hook, which seems
to get called a bit faster than once/second on one machine.

It would be nice to reset the counter whenever user input is made,
but was not clear how to do that with context.input_is_ready().

Example at https://github.com/prompt-toolkit/python-prompt-toolkit/blob/main/examples/prompts/inputhook.py
"""
if self.default_keepalive_ticks < 1:
return
self._keepalive_counter += 1
if self._keepalive_counter > self.default_keepalive_ticks:
self._keepalive_counter = 0
self.logger.debug('keepalive ping')
try:
assert self.sqlexecute is not None
assert self.sqlexecute.conn is not None
self.sqlexecute.conn.ping(reconnect=False)
except Exception as e:
self.logger.debug('keepalive ping error %r', e)

def one_iteration(text: str | None = None) -> None:
inputhook = keepalive_hook if self.default_keepalive_ticks >= 1 else None
if text is None:
try:
assert self.prompt_app is not None
text = self.prompt_app.prompt()
text = self.prompt_app.prompt(inputhook=inputhook)
except KeyboardInterrupt:
return

Expand Down Expand Up @@ -1033,7 +1060,7 @@ def one_iteration(text: str | None = None) -> None:
click.echo("---")
if special.is_timing_enabled():
click.echo(f"Time: {duration:.2f} seconds")
text = self.prompt_app.prompt(default=sql or '')
text = self.prompt_app.prompt(default=sql or '', inputhook=inputhook)
except KeyboardInterrupt:
return
except special.FinishIteration as e:
Expand Down
4 changes: 4 additions & 0 deletions mycli/myclirc
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ default_character_set = utf8mb4
# whether to enable LOAD DATA LOCAL INFILE for connections without --local-infile being set
default_local_infile = False

# How often to send periodic background pings to the server when input is idle. Ticks are
# roughly in seconds, but may be faster. Set to zero to disable. Suggestion: 300.
default_keepalive_ticks = 0

# Sets the desired behavior for handling secure connections to the database server.
# Possible values:
# auto = SSL is preferred. Will attempt to connect via SSL, but will fallback to cleartext as needed.
Expand Down
4 changes: 4 additions & 0 deletions test/myclirc
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ default_character_set = utf8mb4
# whether to enable LOAD DATA LOCAL INFILE for connections without --local-infile being set
default_local_infile = False

# How often to send periodic background pings to the server when input is idle. Ticks are
# roughly in seconds, but may be faster. Set to zero to disable. Suggestion: 300.
default_keepalive_ticks = 0

# Sets the desired behavior for handling secure connections to the database server.
# Possible values:
# auto = SSL is preferred. Will attempt to connect via SSL, but will fallback to cleartext as needed.
Expand Down