Skip to content

Commit cbc1bfe

Browse files
committed
perf(sync): use ThreadPoolExecutor when syncing GitHub team
1 parent 100d221 commit cbc1bfe

File tree

1 file changed

+38
-23
lines changed

1 file changed

+38
-23
lines changed

__meta/synchronizer/synchronizer/services/github_synchronizer.py

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections.abc import Callable
2+
from concurrent.futures import ThreadPoolExecutor
23
from typing import Literal
34

45
from github.GithubException import UnknownObjectException
@@ -17,6 +18,10 @@
1718

1819

1920
class GithubSynchronizer(AbstractSynchronizer):
21+
MAX_WORKERS = (
22+
5 # Maximum number of concurrent workers, 5 seems good but is not tested.
23+
)
24+
2025
ADMIN_SUFFIX = " Admins"
2126

2227
# We can have all teams visible to all members of the organization.
@@ -231,32 +236,42 @@ def sync_members_to_team(
231236
github_team.name,
232237
)
233238

234-
# Check every member who are not invited to the team since
235-
# we also need to check existing members for their roles.
236-
# This does mean that invited members might not have the correct role, but
237-
# it can be corrected during the sync after the invitation is accepted anyways.
238-
for username in self.subtract_invited_members(members, github_team):
239-
try:
240-
current_role = github_team.get_team_membership(username).role
241-
242-
# Skip syncing organization owners' role to member since their role
243-
# will always remain as maintainer.
244-
# https://github.com/orgs/community/discussions/140675#discussioncomment-10875640
245-
if username in self.org_owners and role == "member":
246-
continue
239+
# Haven't find a way to batch retrieve membership roles,
240+
# so we use a thread pool to sync each member to optimize the performance.
241+
with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor:
242+
# Check every member who are not invited to the team since
243+
# we also need to check existing members for their roles.
244+
# This does mean that invited members might not have the correct role, but
245+
# it will be corrected in the sync after the invitation is accepted anyways.
246+
for username in self.subtract_invited_members(members, github_team):
247+
executor.submit(self.sync_member_to_team, github_team, username, role)
248+
249+
def sync_member_to_team(
250+
self,
251+
github_team: GithubTeam,
252+
username: str,
253+
role: Literal["member", "maintainer"],
254+
) -> None:
255+
"""Sync the member to the Github team as the given role."""
256+
try:
257+
current_role = github_team.get_team_membership(username).role
247258

248-
if current_role != role:
249-
self.add_or_update_member_to_team(github_team, username, role)
259+
# Skip syncing organization owners' role to member since their role
260+
# will always remain as maintainer.
261+
# https://github.com/orgs/community/discussions/140675#discussioncomment-10875640
262+
if username in self.org_owners and role == "member":
263+
return
250264

251-
except UnknownObjectException:
265+
if current_role != role:
252266
self.add_or_update_member_to_team(github_team, username, role)
253-
254-
except Exception:
255-
self.logger.exception(
256-
"Error syncing %s to %s GitHub team.",
257-
username,
258-
github_team.name,
259-
)
267+
except UnknownObjectException:
268+
self.add_or_update_member_to_team(github_team, username, role)
269+
except Exception:
270+
self.logger.exception(
271+
"Error syncing %s to %s GitHub team.",
272+
username,
273+
github_team.name,
274+
)
260275

261276
def subtract_invited_members(
262277
self, members: set[str], github_team: GithubTeam

0 commit comments

Comments
 (0)