Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Aug 30, 2025

When running the same playbooks in different task templates simultaneously, both jobs attempt to install required collections into the same temporary project path, causing race conditions and "Directory not empty" errors.

Root Cause

All templates within the same project were sharing the same HOME directory (/tmp/semaphore/project_{projectID}/), causing concurrent ansible-galaxy collection install processes to write to the same $HOME/.ansible/collections/ directory simultaneously.

Solution

Refactored the entire directory structure to be template-based instead of repository-based:

  • Before:

    • Repository clone: /tmp/semaphore/project_{projectID}/repository_{repo_ID}_template_{templateID}
    • HOME: /tmp/semaphore/project_{projectID}/ (shared by all templates in project)
    • Inventory: /tmp/semaphore/project_{projectID}/inventory_{inventory_ID} (project level)
  • After:

    • Template directory: /tmp/semaphore/project_{projectID}/template_{templateID}/
    • Repository clone: /tmp/semaphore/project_{projectID}/template_{templateID}/src/
    • HOME: /tmp/semaphore/project_{projectID}/template_{templateID}/ (isolated per template)
    • Inventory: /tmp/semaphore/project_{projectID}/template_{templateID}/inventory_{inventory_ID} (template level)

This ensures each template gets its own completely isolated directory structure, preventing race conditions when multiple templates within the same project run concurrent ansible-galaxy collection installs.

Cache Management Optimization

The repository cache clearing mechanism has been optimized to be more targeted. Instead of clearing all template directories when a repository changes, the system now queries the database to identify which templates actually use the specific repository and only clears those template directories. This prevents unnecessary cache clearing of unrelated templates.

Changes

  • Updated Repository.GetFullPath() and GetDirName() to use template-based structure with src subdirectory
  • Modified inventory handling to place inventory files within template directories
  • Updated AnsiblePlaybook.makeCmd() to use template-specific HOME directory
  • Optimized Repository.ClearCache() to only clear templates that actually use the repository
  • Updated all existing tests to match new directory structure
  • Added comprehensive test coverage for cache clearing behavior

Fixes #3236.


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

@Copilot Copilot AI changed the title [WIP] Problem: Concurrent Task Template runs in Semaphore cause ansible-galaxy collection install to fail with Directory not empty Fix concurrent ansible-galaxy collection install race condition Aug 30, 2025
@Copilot Copilot AI requested a review from fiftin August 30, 2025 14:31
Copilot finished work on behalf of fiftin August 30, 2025 14:31
@fiftin fiftin marked this pull request as ready for review August 30, 2025 15:44
@fiftin
Copy link
Collaborator

fiftin commented Aug 30, 2025

@copilot Refactor directory structure.

Currently, Semaphore clones each template to directory /projects_{projectID}/repository_{repo_ID}_template_{templateID}.

We need:

  • each template has directory /projects_{projectID}/template_{templateID}
  • HOME=/tmp/semaphore/project_{projectID}/template_{templateID}/
  • inside /projects_{projectID}/template_{templateID} we need to have directory src with cloned template repository.
  • here we need to have cloned inventory file or directory if required inventory_{inventory_ID}, instead of current /projects_{projectID}/template_{templateID}inventory_{inventory_ID}

Copy link
Contributor Author

Copilot AI commented Aug 30, 2025

@copilot Refactor directory structure.

Currently, Semaphore clones each template to directory /projects_{projectID}/repository_{repo_ID}_template_{templateID}.
...

I've completed the directory structure refactoring as requested. The changes implement the new structure:

  • Each template now has directory /projects_{projectID}/template_{templateID}
  • HOME is set to /tmp/semaphore/project_{projectID}/template_{templateID}/
  • Repository content is cloned to src subdirectory within the template directory
  • Inventory files are now placed in the template directory as inventory_{inventory_ID}

All existing tests have been updated and pass with the new structure. The commit that implements this is c37dfad.

@Copilot Copilot AI changed the title Fix concurrent ansible-galaxy collection install race condition Refactor directory structure to prevent ansible-galaxy collection install race conditions Aug 30, 2025
Copilot finished work on behalf of fiftin August 30, 2025 16:09
db/Repository.go Outdated
Comment on lines 36 to 38
// In the new template-based structure, clear all template directories that might contain this repository
// This is a temporary solution - ideally we'd only clear templates that actually use this repository
return util.ClearDir(util.Config.GetProjectTmpDir(r.ProjectID), true, "template_")
Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot only clear templates that actually use this repository

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Modified ClearCache() to only clear template directories for templates that actually use this repository instead of clearing all template directories in the project. The method now queries templates by project ID and only removes directories for templates with matching repository ID.

@Copilot Copilot AI requested a review from fiftin August 30, 2025 16:55
Copilot finished work on behalf of fiftin August 30, 2025 16:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Problem: Concurrent Task Template runs in Semaphore cause ansible-galaxy collection install to fail with Directory not empty
2 participants