Skip to content

Commit 8a3067d

Browse files
authored
Merge pull request #23067 from mvdbeek/store-infra
Add pluggable tool source store infrastructure
2 parents 5279b41 + 4896b7c commit 8a3067d

45 files changed

Lines changed: 6466 additions & 67 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

doc/source/admin/galaxy_options.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,45 @@
420420
:Type: str
421421

422422

423+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
424+
``tool_source_database_connection``
425+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
426+
427+
:Description:
428+
SQLAlchemy connection string for the tool source store, a
429+
rebuildable cache of pre-parsed tool sources kept outside Galaxy's
430+
main database. Multi-host deployments should point every Galaxy
431+
process at the same URI, such as a SQLite file on a shared
432+
filesystem.
433+
Sample default ``sqlite:///<data_dir>/tool_sources.sqlite``.
434+
Populate the store with: python
435+
scripts/tool_source/populate_store.py
436+
For details see
437+
https://docs.galaxyproject.org/en/master/admin/tool_source_storage.html
438+
:Default: ``None``
439+
:Type: str
440+
441+
442+
~~~~~~~~~~~~~~~~~~~~~~
443+
``tool_source_stores``
444+
~~~~~~~~~~~~~~~~~~~~~~
445+
446+
:Description:
447+
Optional named tool source stores referenced from individual
448+
tool_conf files via a top-level ``store="<name>"`` attribute (XML)
449+
or ``store: <name>`` key (YAML). When any tool_conf opts in, the
450+
process composes its named store with the default
451+
(``tool_source_database_connection``) store at runtime, with reads
452+
tried in declared order and writes always landing on the default.
453+
Each entry takes a SQLAlchemy ``url`` and an optional ``read_only:
454+
true`` flag. For SQLite connection-level read-only, use a SQLite
455+
URI with ``mode=ro&uri=true``.
456+
For details see
457+
https://docs.galaxyproject.org/en/master/admin/tool_source_storage.html
458+
:Default: ``None``
459+
:Type: map
460+
461+
423462
~~~~~~~~~~~~~~~~~~~~~~~
424463
``tool_dependency_dir``
425464
~~~~~~~~~~~~~~~~~~~~~~~

doc/source/admin/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Galaxy Deployment & Administration
2222
ai_agents
2323
enable_headers_in_fetch_requests
2424
tool_panel
25+
tool_source_storage
2526
data_tables
2627
mq
2728
dependency_resolvers
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
Tool Source Storage
2+
===================
3+
4+
Overview
5+
--------
6+
7+
By default, Galaxy parses every tool at startup and keeps all of them in
8+
memory. For installations with many tools this:
9+
10+
- Slows down Galaxy startup significantly
11+
- Consumes large amounts of memory in every Galaxy process
12+
13+
Tool source storage addresses this by doing the parsing work once, ahead of
14+
time:
15+
16+
1. Tool sources are pre-parsed (with macros expanded) and stored in a
17+
configurable database backend
18+
2. A lightweight index over the stored tools supports fast tool listings and
19+
search without touching tool files
20+
21+
A toolbox that consumes this store to load tools on demand is planned as
22+
follow-up work; this document covers the store, the populator, and the index
23+
that it will build on.
24+
25+
Configuration
26+
-------------
27+
28+
Tool source storage is configured in ``galaxy.yml``. The following options are available:
29+
30+
Default Store
31+
^^^^^^^^^^^^^
32+
33+
.. code-block:: yaml
34+
35+
galaxy:
36+
# SQLAlchemy URI for storing tool sources.
37+
tool_source_database_connection: sqlite:////srv/galaxy/tool_sources.sqlite
38+
39+
The store lives in a standalone database - a SQLite file under
40+
``<data_dir>/tool_sources.sqlite`` by default - separate from Galaxy's main
41+
database. It is a rebuildable cache: it can be deleted at any time and
42+
recreated by re-running the population script.
43+
44+
Multi-host deployments must point every Galaxy process (web workers *and*
45+
job handlers) at the same store — typically a SQLite file on a shared
46+
filesystem:
47+
48+
.. code-block:: yaml
49+
50+
galaxy:
51+
tool_source_database_connection: sqlite:////shared/galaxy/tool_sources.sqlite
52+
53+
Any other SQLAlchemy-supported database (e.g. PostgreSQL) works as well.
54+
55+
Per-conf Store Routing (CVMFS Recipe)
56+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
57+
58+
Individual ``tool_conf`` files can opt into a *named* tool source store,
59+
distinct from the global default. The typical use case is shipping a
60+
read-only SQLite bundle on CVMFS alongside a tool_conf, so worker
61+
processes can resolve every tool in that conf with local-cached lookups
62+
instead of one network round-trip per JSON file.
63+
64+
Declare the named stores under the top-level ``tool_source_stores`` key in
65+
``galaxy.yml``. Each entry takes a SQLAlchemy ``url`` and optional
66+
``read_only`` flag. SQLite is the typical choice for CVMFS bundles (single
67+
self-contained file), but any SQLAlchemy-supported database works:
68+
69+
.. code-block:: yaml
70+
71+
galaxy:
72+
tool_source_database_connection: sqlite:////srv/galaxy/tool_sources.sqlite
73+
tool_source_stores:
74+
cvmfs_main:
75+
url: sqlite:///file:/cvmfs/example.org/tools/sources.sqlite?mode=ro&uri=true
76+
read_only: true
77+
site_shared:
78+
url: sqlite:///file:/shared/galaxy/tool_sources.sqlite?mode=ro&uri=true
79+
read_only: true
80+
81+
Then point the tool_conf at it via the root element's ``store`` attribute
82+
(XML) or top-level key (YAML):
83+
84+
.. code-block:: xml
85+
86+
<?xml version="1.0"?>
87+
<toolbox store="cvmfs_main">
88+
<section id="cvmfs_tools" name="CVMFS Tools">
89+
<tool file="bwa/bwa.xml"/>
90+
...
91+
</section>
92+
</toolbox>
93+
94+
At startup, Galaxy inspects every ``tool_conf`` for the attribute, builds
95+
the referenced stores, and wraps them with the writable default in a
96+
composite store. Reads are tried in declared order (first hit wins) and
97+
writes always go to the default store. If no tool_conf opts in, the
98+
default store is used directly with zero overhead.
99+
100+
**Building the bundle**
101+
102+
Build the SQLite file from a writable host before shipping it:
103+
104+
.. code-block:: console
105+
106+
$ python scripts/tool_source/populate_store.py -c galaxy.yml --target cvmfs_main
107+
108+
Use ``--target`` to restrict population to a single named store; without
109+
it, ``populate_store.py`` populates **every writable store** referenced
110+
from a tool_conf in the same run.
111+
112+
Once the bundle is in place on CVMFS (or any read-only mount), restart
113+
Galaxy. The ``read_only: true`` flag prevents Galaxy from writing through that
114+
store. For SQLite connection-level read-only, use ``mode=ro&uri=true`` in the
115+
SQLite URI as shown above.
116+
117+
Populating the Tool Source Store
118+
--------------------------------
119+
120+
After configuring tool source storage, you need to populate it with your tools.
121+
Use the ``populate_store.py`` script:
122+
123+
Basic Usage
124+
^^^^^^^^^^^
125+
126+
.. code-block:: console
127+
128+
$ python scripts/tool_source/populate_store.py --config /path/to/galaxy.yml
129+
130+
Deployments that install Galaxy from packages get the same command as the
131+
``galaxy-populate-tool-source-store`` console script (shipped with the
132+
``galaxy-app`` package), so no Galaxy source checkout is needed:
133+
134+
.. code-block:: console
135+
136+
$ galaxy-populate-tool-source-store --config /path/to/galaxy.yml
137+
138+
This will:
139+
140+
1. Discover tools from your tool configs (uses the same logic as Galaxy startup)
141+
2. Parse each tool (with macro expansion) and compute a content hash
142+
3. Store the tool sources in the configured backend (skipping unchanged tools)
143+
144+
Note: ``--config`` is required; the script does not assume a default path.
145+
146+
Command Line Options
147+
^^^^^^^^^^^^^^^^^^^^
148+
149+
.. code-block:: console
150+
151+
$ python scripts/tool_source/populate_store.py --help
152+
153+
Options:
154+
--config, -c PATH Galaxy configuration file (required)
155+
--dry-run Show what would be stored without storing
156+
--incremental Only store new/changed tools (default)
157+
--full Force re-store of all tools
158+
--tool-id PATTERN Only process tools whose ID contains PATTERN
159+
--parallel, -j N Number of parallel workers (default: 4)
160+
--rebuild-index Rebuild the tool index after population
161+
--target NAME Restrict to a single named store from
162+
tool_source_stores (or '__default__'). Without
163+
this, every writable store is populated.
164+
--verbose, -v Verbose output
165+
--watch, -w Watch tool directories and send reload notifications
166+
--watch-polling Use polling observer (for NFS/CVMFS/network FS)
167+
168+
Examples
169+
^^^^^^^^
170+
171+
**Initial population:**
172+
173+
.. code-block:: console
174+
175+
$ python scripts/tool_source/populate_store.py -c /path/to/galaxy.yml
176+
177+
**Force re-store everything (e.g., after a parser change):**
178+
179+
.. code-block:: console
180+
181+
$ python scripts/tool_source/populate_store.py -c galaxy.yml --full
182+
183+
**Process only a subset of tools:**
184+
185+
.. code-block:: console
186+
187+
$ python scripts/tool_source/populate_store.py -c galaxy.yml --tool-id samtools
188+
189+
Automation with Cron
190+
^^^^^^^^^^^^^^^^^^^^
191+
192+
For installations where tools are frequently updated, you can run the population
193+
script on a schedule:
194+
195+
.. code-block:: cron
196+
197+
# Update tool source store every hour (incremental is the default)
198+
0 * * * * /path/to/galaxy/.venv/bin/python /path/to/galaxy/scripts/tool_source/populate_store.py -c /path/to/galaxy.yml >> /var/log/galaxy/tool_source_update.log 2>&1
199+
200+
Watch Mode (Live Updates)
201+
^^^^^^^^^^^^^^^^^^^^^^^^^
202+
203+
As an alternative to cron, you can run the population script in watch mode to
204+
keep the store continuously up to date. This uses ``watchdog`` to monitor tool
205+
directories for changes and automatically updates the store, then sends a
206+
notification via Kombu to trigger cache reloads in all Galaxy processes.
207+
208+
.. code-block:: console
209+
210+
$ python scripts/tool_source/populate_store.py --config galaxy.yml --watch
211+
212+
Watch mode options:
213+
214+
- ``--watch, -w`` - Enable watch mode
215+
- ``--watch-polling`` - Use polling observer (required for network filesystems like NFS/CVMFS)
216+
217+
Example with polling for network filesystem:
218+
219+
.. code-block:: console
220+
221+
$ python scripts/tool_source/populate_store.py -c galaxy.yml --watch --watch-polling
222+
223+
**Requirements:**
224+
225+
- The ``watchdog`` library must be installed: ``pip install watchdog``
226+
- Galaxy must have ``amqp_internal_connection`` configured for Kombu notifications
227+
- All Galaxy processes must be connected to the same AMQP broker
228+
229+
When a tool XML file changes, watch mode will:
230+
231+
1. Detect the file change (with debouncing to handle rapid edits)
232+
2. Re-parse the tool and update the store
233+
3. Send a ``reload_tool_source_cache`` control message via Kombu
234+
4. All Galaxy processes will invalidate their local caches
235+
236+
This is useful for:
237+
238+
- Installations using shared storage where tools may be updated externally
239+
- CI/CD pipelines that deploy tool updates
240+
- Development environments where tools are being actively edited
241+
242+
Troubleshooting
243+
---------------
244+
245+
Tools not appearing in the index
246+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
247+
248+
1. Re-run the population script with verbose output:
249+
250+
.. code-block:: console
251+
252+
$ python scripts/tool_source/populate_store.py -c galaxy.yml -v
253+
254+
2. Check for parsing errors in the Galaxy log
255+
256+
Populating an existing installation
257+
-----------------------------------
258+
259+
To set up tool source storage on an existing Galaxy installation:
260+
261+
1. Add the configuration to ``galaxy.yml``:
262+
263+
.. code-block:: yaml
264+
265+
galaxy:
266+
tool_source_database_connection: sqlite:////srv/galaxy/tool_sources.sqlite
267+
268+
2. Run the population script:
269+
270+
.. code-block:: console
271+
272+
$ python scripts/tool_source/populate_store.py -c /path/to/galaxy.yml
273+
274+
3. Restart Galaxy

doc/source/dev/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ A multi-hour long video playlist covering these slides can be found at
2020
data_managers
2121
data_source
2222
data_types
23+
tool_source_storage
2324
faq
2425
writing_tests
2526
debugging_tests

0 commit comments

Comments
 (0)