Skip to content

Read store repository app folders in parallel#6963

Open
frenck wants to merge 1 commit into
mainfrom
frenck/store-parallel-repo-read
Open

Read store repository app folders in parallel#6963
frenck wants to merge 1 commit into
mainfrom
frenck/store-parallel-repo-read

Conversation

@frenck

@frenck frenck commented Jun 19, 2026

Copy link
Copy Markdown
Member

Proposed change

StoreData.update() reads each repository's app folder in sequence: the core repository, the local repository, then every custom git repository one after another. Each read does a recursive **/config.* glob and parses every add-on config for that repository, so the total time grows with the number of repositories. This runs on every store reload (startup, adding/removing a repository, and the periodic reload), and is more expensive with large or network-backed repositories.

The repositories are independent and each produces apps under its own repository-prefixed slug ({repository}_{slug}), so this reads all app folders concurrently with asyncio.gather instead of awaiting them one by one. The results are merged in the original order (core, local, then git repositories), so behavior is unchanged; only the wall-clock time drops toward the slowest single repository instead of the sum of all of them.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (which adds functionality to the supervisor)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

  • This PR fixes or closes issue: fixes #
  • This PR is related to issue:
  • Link to documentation pull request:
  • Link to cli pull request:
  • Link to client library pull request:

Checklist

  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • The code has been formatted using Ruff (ruff format supervisor tests)
  • Tests have been added to verify that the new code works.

If API endpoints or add-on configuration are added/changed:

StoreData.update reads each repository's app folder in sequence: the
core repository, the local repository, then every custom git repository
one after another. Each read does a recursive config glob and parses all
add-on configs for that repository, so the total time grows with the
number of repositories.

The repositories are independent and each produces apps under its own
repository-prefixed slug, so read all app folders concurrently with
asyncio.gather instead. Results are merged in the original order, so the
behavior is unchanged.
@frenck frenck added the refactor A code change that neither fixes a bug nor adds a feature label Jun 19, 2026
@frenck frenck requested a review from Copilot June 19, 2026 10:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes the Supervisor’s store reload path by changing StoreData.update() to read add-on (app) folders from the core, local, and custom git repositories concurrently, reducing store reload wall-clock time as the number of repositories grows.

Changes:

  • Discover custom git repositories, then read all repository app folders concurrently via asyncio.gather.
  • Merge per-repository app dictionaries in the same order as before (core → local → git repos) to preserve precedence behavior.

Comment thread supervisor/store/data.py
Comment on lines +131 to +145
# Read all repository app folders in parallel; they are independent and
# each produces apps under its own repository-prefixed slug.
folders = [
(self.sys_config.path_apps_core, REPOSITORY_CORE),
(self.sys_config.path_apps_local, REPOSITORY_LOCAL),
*((repo.path, repo.slug) for repo in git_repositories),
]
folder_apps = await asyncio.gather(
*(self._read_apps_folder(path, slug) for path, slug in folders)
)

# Merge in folder order to preserve the previous precedence
apps: dict[str, dict[str, Any]] = {}
for result in folder_apps:
apps.update(result)

@agners agners left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so behavior is unchanged; only the wall-clock time drops toward the slowest single repository instead of the sum of all of them.

Is that proven? 🤔

Typically such recursive search in directory trees leads to lots of random I/O. I am quite sure that at least on spinning disks doing such operation in parallel actually kills performance. Probably modern SSD with multiple I/O queues can actually parallelize such operations, but I'd guess most cheaper SSD and eMMC/SD cards run with a single I/O queue, where running these in parallel most likely leads to no or negligible performance differences.

Unless measurements really show that this improves reload time on typical hardware in real world, I'd rather not parallelize workloads with lots of random I/O.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed refactor A code change that neither fixes a bug nor adds a feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants