Compare commits
2 Commits
1fbfa8010b
...
20227dde4d
| Author | SHA1 | Date | |
|---|---|---|---|
| 20227dde4d | |||
| b5d5404f73 |
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "sessions-sublime"
|
||||
version = "0.7.28"
|
||||
version = "0.7.29"
|
||||
description = "Sublime-facing Python code for Sessions."
|
||||
requires-python = ">=3.8"
|
||||
license = {text = "MIT"}
|
||||
|
||||
12
rust/Cargo.lock
generated
12
rust/Cargo.lock
generated
@@ -221,7 +221,7 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||
|
||||
[[package]]
|
||||
name = "local_bridge"
|
||||
version = "0.7.28"
|
||||
version = "0.7.29"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"glob",
|
||||
@@ -432,7 +432,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "session_helper"
|
||||
version = "0.7.28"
|
||||
version = "0.7.29"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"notify",
|
||||
@@ -443,7 +443,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "session_protocol"
|
||||
version = "0.7.28"
|
||||
version = "0.7.29"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"serde",
|
||||
@@ -452,14 +452,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sessions_askpass"
|
||||
version = "0.7.28"
|
||||
version = "0.7.29"
|
||||
dependencies = [
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sessions_native"
|
||||
version = "0.7.28"
|
||||
version = "0.7.29"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"serde_json",
|
||||
@@ -772,7 +772,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "workspace_identity"
|
||||
version = "0.7.28"
|
||||
version = "0.7.29"
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
|
||||
@@ -12,7 +12,7 @@ resolver = "2"
|
||||
[workspace.package]
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
version = "0.7.28"
|
||||
version = "0.7.29"
|
||||
authors = ["Myeongseon Choi <key262yek@gmail.com>"]
|
||||
repository = "https://git.teahaven.kr/sublime-rs/sessions"
|
||||
homepage = "https://git.teahaven.kr/sublime-rs/sessions"
|
||||
|
||||
@@ -306,6 +306,15 @@ _MIRROR_QUEUE_MAX = 8
|
||||
_EAGER_HYDRATE_INFLIGHT: Set[str] = set()
|
||||
_EAGER_HYDRATE_INFLIGHT_LOCK = threading.Lock()
|
||||
|
||||
# ``sessions.refresh_git_state`` previously rode the shared background
|
||||
# worker; one of its ``exec/once`` calls has a 305 s timeout (long ``git
|
||||
# fetch``) which head-of-line-blocked every later task — including the
|
||||
# ``prioritize=True`` ``hydrate_open_file`` fired when the user opens a
|
||||
# remote file. v0.7.28 same per-key in-flight pattern as eager-hydrate
|
||||
# moves the refresh to its own daemon thread per cache_key.
|
||||
_REFRESH_GIT_STATE_INFLIGHT: Set[str] = set()
|
||||
_REFRESH_GIT_STATE_INFLIGHT_LOCK = threading.Lock()
|
||||
|
||||
|
||||
def _mirror_queue_pressure(queue_size: int, dropped: int) -> str:
|
||||
return _rust_ffi.mirror_queue_pressure(
|
||||
@@ -1851,12 +1860,20 @@ def _schedule_sidebar_placeholder_hydrate(view: object) -> None:
|
||||
|
||||
_set_timeout(finish, 50)
|
||||
|
||||
_run_in_background(
|
||||
work,
|
||||
prioritize=True,
|
||||
task_key="hydrate:{}".format(path_str),
|
||||
task_label="hydrate_open_file",
|
||||
)
|
||||
# User-facing critical path: hydrate the file the user just opened.
|
||||
# Run on a dedicated daemon thread so neither ``eager_hydrate`` nor
|
||||
# ``sessions.refresh_git_state`` (which can block the shared worker
|
||||
# for up to 5 minutes on a slow ``git fetch``) can stall it. The
|
||||
# ``_HYDRATE_IN_FLIGHT`` set above already dedupes per-view, so
|
||||
# losing the queue's task_key dedup costs nothing.
|
||||
if bool(getattr(sublime, "_sessions_test_sync", False)):
|
||||
work()
|
||||
else:
|
||||
threading.Thread(
|
||||
target=work,
|
||||
daemon=True,
|
||||
name="sessions-hydrate-open-file-{}".format(view_id),
|
||||
).start()
|
||||
|
||||
|
||||
class SessionsSidebarPlaceholderHydrateListener(sublime_plugin.EventListener):
|
||||
@@ -7322,11 +7339,36 @@ def _run_track_g_refresh(
|
||||
|
||||
_set_timeout(finish, 0)
|
||||
|
||||
_run_in_background(
|
||||
work,
|
||||
task_label="sessions.refresh_git_state",
|
||||
task_key="sessions_refresh_git_state:{}".format(context.cache_key),
|
||||
)
|
||||
# Git refresh issues an ``exec/once`` with a 305 s timeout (slow
|
||||
# network ``git fetch``); on the shared background worker it would
|
||||
# head-of-line-block ``hydrate_open_file`` and other prioritised
|
||||
# tasks. Per-cache_key in-flight set + dedicated daemon thread
|
||||
# mirrors the eager-hydrate pattern.
|
||||
cache_key = context.cache_key
|
||||
if bool(getattr(sublime, "_sessions_test_sync", False)):
|
||||
work()
|
||||
return
|
||||
with _REFRESH_GIT_STATE_INFLIGHT_LOCK:
|
||||
if cache_key in _REFRESH_GIT_STATE_INFLIGHT:
|
||||
_trace_event("git.refresh_state_skip_inflight", cache_key=cache_key)
|
||||
return
|
||||
_REFRESH_GIT_STATE_INFLIGHT.add(cache_key)
|
||||
|
||||
def _runner() -> None:
|
||||
try:
|
||||
work()
|
||||
except Exception:
|
||||
_trace_event("git.refresh_state_thread_error", cache_key=cache_key)
|
||||
print("[Sessions] Git refresh thread failed.", file=sys.stderr)
|
||||
finally:
|
||||
with _REFRESH_GIT_STATE_INFLIGHT_LOCK:
|
||||
_REFRESH_GIT_STATE_INFLIGHT.discard(cache_key)
|
||||
|
||||
threading.Thread(
|
||||
target=_runner,
|
||||
daemon=True,
|
||||
name="sessions-refresh-git-{}".format(cache_key),
|
||||
).start()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -644,9 +644,16 @@ def test_hydrate_precheck_error_skips_read_for_active_view(
|
||||
assert opened_calls == []
|
||||
|
||||
|
||||
def test_hydrate_schedule_sets_path_scoped_task_key(
|
||||
def test_hydrate_schedule_runs_synchronously_in_test_mode(
|
||||
tmp_path: Path, monkeypatch
|
||||
) -> None:
|
||||
"""v0.7.28+ hydrate-on-open runs on a dedicated daemon thread per
|
||||
view (not the shared background queue) so it cannot be head-of-
|
||||
line-blocked by long-running tasks (eager_hydrate,
|
||||
sessions.refresh_git_state). Under ``_sessions_test_sync`` the
|
||||
function falls back to running work() inline; we verify the
|
||||
expected ``open_remote_file_into_local_cache`` invocation reaches
|
||||
the right remote path with the right view-id dedup."""
|
||||
context = commands._WorkspaceContext(
|
||||
settings=SessionsSettings(),
|
||||
recent_entry=RecentWorkspace(
|
||||
@@ -672,22 +679,38 @@ def test_hydrate_schedule_sets_path_scoped_task_key(
|
||||
)
|
||||
view.id = lambda: 43
|
||||
|
||||
captured: List[Optional[str]] = []
|
||||
captured_remotes: List[str] = []
|
||||
|
||||
def fake_open(host, **kwargs):
|
||||
captured_remotes.append(kwargs["remote_absolute_path"])
|
||||
return commands.OpenFileResult(
|
||||
outcome=commands.OpenOutcome.OK,
|
||||
local_cache_path=kwargs["local_cache_path"],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(commands, "_mirror_hydrate_placeholders_on_open", lambda: True)
|
||||
monkeypatch.setattr(commands, "_workspace_context", lambda *args, **kwargs: context)
|
||||
monkeypatch.setattr(
|
||||
commands, "_workspace_runtime_connected", lambda *args, **kwargs: True
|
||||
)
|
||||
monkeypatch.setattr(commands, "_active_view", lambda window: view)
|
||||
monkeypatch.setattr(
|
||||
commands,
|
||||
"_run_in_background",
|
||||
lambda target, *args, **kwargs: captured.append(kwargs.get("task_key")),
|
||||
"_precheck_remote_file_openability",
|
||||
lambda **kwargs: commands._HydratePrecheckOutcome(
|
||||
proceed=True, stat_metadata=None
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(commands, "open_remote_file_into_local_cache", fake_open)
|
||||
monkeypatch.setattr(commands, "_apply_hydrate_result", lambda **kwargs: None)
|
||||
monkeypatch.setattr(commands, "_set_timeout", lambda fn, ms: fn())
|
||||
monkeypatch.setattr(commands.sublime, "_sessions_test_sync", True, raising=False)
|
||||
commands._HYDRATE_IN_FLIGHT.clear()
|
||||
|
||||
commands._schedule_sidebar_placeholder_hydrate(view)
|
||||
|
||||
assert captured == ["hydrate:{}".format(str(local_file))]
|
||||
assert captured_remotes == ["/srv/ws/app.py"]
|
||||
assert 43 in commands._HYDRATE_IN_FLIGHT
|
||||
|
||||
|
||||
def test_hydrate_schedule_fetches_for_nonexistent_cache_file(
|
||||
@@ -729,23 +752,38 @@ def test_hydrate_schedule_fetches_for_nonexistent_cache_file(
|
||||
)
|
||||
view.id = lambda: 99
|
||||
|
||||
captured: List[Optional[str]] = []
|
||||
captured_remotes: List[str] = []
|
||||
|
||||
def fake_open(host, **kwargs):
|
||||
captured_remotes.append(kwargs["remote_absolute_path"])
|
||||
return commands.OpenFileResult(
|
||||
outcome=commands.OpenOutcome.OK,
|
||||
local_cache_path=kwargs["local_cache_path"],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(commands, "_mirror_hydrate_placeholders_on_open", lambda: True)
|
||||
monkeypatch.setattr(commands, "_workspace_context", lambda *args, **kwargs: context)
|
||||
monkeypatch.setattr(
|
||||
commands, "_workspace_runtime_connected", lambda *args, **kwargs: True
|
||||
)
|
||||
monkeypatch.setattr(commands, "_active_view", lambda window: view)
|
||||
monkeypatch.setattr(
|
||||
commands,
|
||||
"_run_in_background",
|
||||
lambda target, *args, **kwargs: captured.append(kwargs.get("task_key")),
|
||||
"_precheck_remote_file_openability",
|
||||
lambda **kwargs: commands._HydratePrecheckOutcome(
|
||||
proceed=True, stat_metadata=None
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(commands, "open_remote_file_into_local_cache", fake_open)
|
||||
monkeypatch.setattr(commands, "_apply_hydrate_result", lambda **kwargs: None)
|
||||
monkeypatch.setattr(commands, "_set_timeout", lambda fn, ms: fn())
|
||||
monkeypatch.setattr(commands.sublime, "_sessions_test_sync", True, raising=False)
|
||||
commands._HYDRATE_IN_FLIGHT.clear()
|
||||
|
||||
commands._schedule_sidebar_placeholder_hydrate(view)
|
||||
|
||||
assert captured == ["hydrate:{}".format(str(local_file))], (
|
||||
"goto-def on uncached file must still enqueue a hydrate fetch"
|
||||
assert captured_remotes == ["/srv/ws/src/module.py"], (
|
||||
"goto-def on uncached file must still trigger a hydrate fetch"
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user