|
| 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 |
0 commit comments