Skip to content

Conversation

cathteng
Copy link
Member

@cathteng cathteng commented Jul 14, 2025

We are hitting the processing deadline of 60 seconds for link_all_repos. We can improve the performance by making more bulk queries.

Changes

  1. Add RepositoryConfig type
  2. Make 1 function to create repos for an org. Previously we were repeatedly calling the same function (IntegrationRepositoryProvider.create_repository) with possibly many RPC calls inside
  3. Make a constant number of queries per integration to link all repos (previously this was not constant) + as many queries as new repos
  4. Remove unnecessary metrics now that we are using the context manager

Unchanged

  1. We still attempt to create each new Repository individually. This is because we may need to take actions for each Repository that fails creation. Django's bulk_create will fail and rollback all changes if there is an error. Alternatively, we can pass ignore_conflicts=True to bulk_create, but then we wouldn't be able to see which ones failed.

Fixes ECO-801

@cathteng cathteng requested review from a team as code owners July 14, 2025 22:34
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Jul 14, 2025
cursor[bot]

This comment was marked as outdated.

@cathteng cathteng requested a review from GabeVillalobos July 14, 2025 22:42
Copy link
Member

@GabeVillalobos GabeVillalobos left a comment

Choose a reason for hiding this comment

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

Changes look mostly good, just a question on partial failure handling.

lifecycle.record_halt(str(LinkAllReposHaltReason.RATE_LIMITED))
return

metrics.incr(f"{integration_key}.link_all_repos.api_error")
Copy link
Member

Choose a reason for hiding this comment

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

Are there any dashboards we need to update that use this?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not aware of any monitoring we have on this, plus we should be using the lifecycle metrics anyway

repo_config=config, organization=rpc_org
)
success = True
repo_configs.append(get_repo_config(repo, integration_id))
Copy link
Member

Choose a reason for hiding this comment

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

👏🏼 Much cleaner

Comment on lines +104 to +107
lifecycle.record_halt(
str(LinkAllReposHaltReason.REPOSITORY_NOT_CREATED),
{"missing_repos": missing_repos, "integration_id": integration_id},
)
Copy link
Member

Choose a reason for hiding this comment

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

Are there any other partial failures cases we need to worry about?

What does integration_repo_provider.create_repositories do if any of these repo creations fail?

Copy link
Member Author

@cathteng cathteng Jul 14, 2025

Choose a reason for hiding this comment

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

The only case is where some fail and some succeed. Previously we would actually mark it as success if any repo was created, but here we only mark it as success if ALL repos are created/updated successfully.

If repo creation fails, we now raise an exception with the failed repos and mark it as a halt

Copy link

codecov bot commented Jul 14, 2025

Codecov Report

Attention: Patch coverage is 72.88136% with 32 lines in your changes missing coverage. Please review.

✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...rc/sentry/integrations/services/repository/impl.py 5.55% 17 Missing ⚠️
...sentry/plugins/providers/integration_repository.py 80.95% 12 Missing ⚠️
...y/integrations/github/tasks/test_link_all_repos.py 75.00% 2 Missing ⚠️
...sentry/integrations/services/repository/service.py 75.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #95494      +/-   ##
==========================================
+ Coverage   77.79%   82.71%   +4.91%     
==========================================
  Files       10535    10535              
  Lines      607265   607335      +70     
  Branches    23794    23794              
==========================================
+ Hits       472431   502333   +29902     
+ Misses     134449   104617   -29832     
  Partials      385      385              

cursor[bot]

This comment was marked as outdated.

Base automatically changed from cathy/repo/bulk-update to master July 14, 2025 23:57
Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Bug: Duplicate Halt Events in Repo Linking

The link_all_repos task can record a halt event twice for the same execution. This occurs when create_repositories() raises a RepoExistsError and the missing_repos list is also non-empty. The RepoExistsError handler records a halt but continues execution, allowing a second halt to be recorded by the missing_repos check. This leads to duplicate lifecycle events and inaccurate metrics.

src/sentry/integrations/github/tasks/link_all_repos.py#L92-L107

try:
integration_repo_provider.create_repositories(
configs=repo_configs, organization=rpc_org
)
except RepoExistsError as e:
lifecycle.record_halt(
str(LinkAllReposHaltReason.REPOSITORY_NOT_CREATED),
{"missing_repos": e.repos, "integration_id": integration_id},
)
if missing_repos:
lifecycle.record_halt(
str(LinkAllReposHaltReason.REPOSITORY_NOT_CREATED),
{"missing_repos": missing_repos, "integration_id": integration_id},
)

Fix in CursorFix in Web


Bug: Repository Update Fails to Set Provider

The _update_repository method fails to update the provider field for existing repositories. Unlike the previous create_repository logic which explicitly set provider: self.id during updates, the new method only applies fields from RepositoryConfig, which does not include provider. This omission causes inconsistencies and prevents the "migration" of repositories to a new provider.

src/sentry/plugins/providers/integration_repository.py#L206-L212

def _update_repository(self, repo: RpcRepository, config: RepositoryConfig):
repo.status = ObjectStatus.ACTIVE
for field_name, field_value in config.items():
setattr(repo, field_name, field_value)
return repo

Fix in CursorFix in Web


Was this report helpful? Give feedback by reacting with 👍 or 👎

@cathteng cathteng merged commit bb80ef6 into master Jul 15, 2025
64 checks passed
@cathteng cathteng deleted the cathy/repo/ref-link-all branch July 15, 2025 16:15
@github-actions github-actions bot locked and limited conversation to collaborators Jul 31, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Scope: Backend Automatically applied to PRs that change backend components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants