mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
LazyToolBox.invalidate_index_cache: register new entries as LazyTool stubs
When a peer process runs the populator (shed install reroute in commit 12, ``reset_shed_tools`` in commit 13, ``--watch`` mode), it broadcasts ``reload_tool_source_cache`` which lands in every Galaxy process's ``invalidate_index_cache``. Until now that only re-read the index — the new ids were reachable via ``get_tool`` lookups but didn't appear in ``_tools_by_id`` until the next boot, so ``/api/tools`` under-reported. Two new helpers close the gap: - ``_register_new_index_entries_as_stubs`` walks the freshly-loaded ``_tool_index.entries`` and registers anything not already in ``_tools_by_id``. - ``_register_lazy_entry(entry)`` is the inverse of the existing ``_register_loaded_tool``: builds a ``LazyTool`` stub, populates ``_tools_by_id`` / ``_tool_versions_by_id`` / ``_tools_by_old_id`` / ``_tools_by_uuid``, assigns ``_lineage`` via ``LazyLineageMap.get``, and slots the stub into ``_tool_panel`` under its declared ``panel_section_id`` (creating the ``ToolSection`` if absent). This is the broadcast-side hook that makes peer-process installs visible in this process without waiting for a full toolbox reload. 22/22 unit tests still pass.
This commit is contained in:
@@ -867,6 +867,75 @@ class LazyToolBox(ToolBox):
|
||||
# on-disk index under us, and the next ``search_tools`` should
|
||||
# re-open it.
|
||||
self._whoosh_search_index = None
|
||||
# Wire newly-indexed entries (e.g. shed-install partial updates from
|
||||
# a peer process) into this process's in-memory registries as
|
||||
# ``LazyTool`` stubs. Without this, ``/api/tools`` would return the
|
||||
# new ids only after the next full toolbox boot.
|
||||
self._register_new_index_entries_as_stubs()
|
||||
|
||||
def _register_new_index_entries_as_stubs(self) -> None:
|
||||
"""For every index entry not yet in ``_tools_by_id``, build a
|
||||
``LazyTool`` stub, slot it into the toolbox registries, and place it
|
||||
under its declared panel section.
|
||||
|
||||
Mirrors what the eager walk does at boot for each ``<tool>`` element,
|
||||
but for a single entry already fully described by the populator.
|
||||
"""
|
||||
if self._tool_index is None:
|
||||
return
|
||||
for tool_id, entry in self._tool_index.entries.items():
|
||||
if tool_id in self._tools_by_id:
|
||||
continue
|
||||
try:
|
||||
self._register_lazy_entry(entry)
|
||||
except Exception as e:
|
||||
log.warning("Failed to register new index entry %s: %s", tool_id, e)
|
||||
|
||||
def _register_lazy_entry(self, entry: ToolIndexEntry) -> "LazyTool":
|
||||
"""Construct + slot a ``LazyTool`` stub for ``entry``.
|
||||
|
||||
Inverse of :meth:`_register_loaded_tool`: same bookkeeping, but for
|
||||
the stub side. Used by :meth:`invalidate_index_cache` when a
|
||||
peer-process populator run added new entries that this process should
|
||||
surface immediately.
|
||||
"""
|
||||
from galaxy.tool_util.toolbox.panel import ToolSection
|
||||
|
||||
stub = LazyTool(
|
||||
entry,
|
||||
materialize_callback=self._materialize_for_lazy_tool,
|
||||
is_admin_user=self.app.config.is_admin_user,
|
||||
)
|
||||
tool_id = entry.id
|
||||
self._tools_by_id[tool_id] = stub # type: ignore[assignment]
|
||||
version = entry.version
|
||||
self._tool_versions_by_id.setdefault(tool_id, {})[version or ""] = stub # type: ignore[assignment]
|
||||
old_id = stub.old_id
|
||||
if old_id and old_id != tool_id:
|
||||
bucket = self._tools_by_old_id.setdefault(old_id, [])
|
||||
if not any(getattr(t, "id", None) == tool_id for t in bucket):
|
||||
bucket.append(stub) # type: ignore[arg-type]
|
||||
if entry.uuid:
|
||||
self._tools_by_uuid[entry.uuid] = stub # type: ignore[assignment]
|
||||
# Lineage: LazyLineageMap builds it from entries_by_version, which the
|
||||
# populator wrote on the previous step, so .get() returns the right
|
||||
# ToolLineage; register() is the fallback for an as-yet-unseen id.
|
||||
stub._lineage = self._lineage_map.get(tool_id) or self._lineage_map.register(stub)
|
||||
# Place into the panel. The populator stamped panel_section_id /
|
||||
# panel_section_name onto the entry; create the ToolSection if it
|
||||
# doesn't already exist (peer-process install of the first tool in
|
||||
# a new section).
|
||||
section_id = entry.panel_section_id
|
||||
if section_id:
|
||||
section_key = f"section_{section_id}"
|
||||
section = self._tool_panel.get(section_key)
|
||||
if not isinstance(section, ToolSection):
|
||||
section = ToolSection({"id": section_id, "name": entry.panel_section_name or section_id})
|
||||
self._tool_panel[section_key] = section
|
||||
section.elems.append_tool(stub)
|
||||
else:
|
||||
self._tool_panel[f"tool_{tool_id}"] = stub # type: ignore[assignment]
|
||||
return stub
|
||||
|
||||
def _register_loaded_tool(self, tool: "Tool") -> None:
|
||||
"""Register a lazily-loaded tool in the toolbox registries."""
|
||||
|
||||
Reference in New Issue
Block a user