-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
배치 잡 스케줄러 (feat: 슬랙 멤버 동기화) #24
Conversation
be2503a
to
3264b76
Compare
run: pipx install poetry | ||
run: | | ||
pipx install poetry | ||
poetry config virtualenvs.in-project true --local |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
기록) pre-commit 테스트 스텝에서 PyRight 가상환경 경로 탐색 실패 이슈로 추가
aiohttp = "^3.9.5" | ||
schedule = "^1.2.2" | ||
pytz = "^2024.1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aiohttp - slack_sdk.web.async_client.AsyncWebClient 에 필요
schedule, pytz - 배치 잡 스케줄링에 필요
user.first_name = slack_member.profile.first_name or user.first_name | ||
user.last_name = slack_member.profile.last_name or user.last_name | ||
user.slack_email = slack_member.profile.email or user.slack_email | ||
user.phone_number = slack_member.profile.phone or user.phone_number | ||
user.image_url = slack_member.profile.image_192 or user.image_url | ||
user.github_id = slack_member.profile.github_id or user.github_id | ||
# user.position = slack_member.profile.position or user.position | ||
user.generation = slack_member.profile.generation or user.generation | ||
user.is_member = True | ||
self.user_repository.update_user(user) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
None 값이 기존 값을 덮어씌우지 않도록 개선
if settings.is_dev: | ||
scheduler.every().saturday.at("00:00", "Asia/Seoul").do(slack_main) | ||
if settings.is_prod: | ||
scheduler.every().sunday.at("00:00", "Asia/Seoul").do(slack_main) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
버그 발생 시 조기 탐지를 위해 dev에서 하루 먼저 실행
scheduler.every().sunday.at("00:00", "Asia/Seoul").do(slack_main) | ||
while True: | ||
# 최소 주기를 60초로 설정 | ||
await asyncio.sleep(60) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
비록 현재 유일한 배치잡인 슬랙 동기화 작업은 1주일마다 실행하지만, 실행 주기의 정밀도와 추후에 더 짧은 주기의 배치잡이 추가될 것을 감안하여 1분으로 설정
실행할 잡이 없을 때 run_pending
은 충분히 간단한 작업이므로 1분이면 충분히 길다고 판단됨
user_service: UserService = Depends(), | ||
slack_api_service: AsyncSlackApiService = Depends(), | ||
): | ||
members_to_create = await slack_api_service.get_members() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
멤버 조회 로직을 별도 서비스로 분리
try: | ||
asyncio.create_task(solver.run(create_users_from_slack)) | ||
except RuntimeError: | ||
asyncio.run(solver.run(create_users_from_slack)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
asyncio 루프 안에서 실행되는 케이스 대응
class CustomFieldId(StrEnum): | ||
GITHUB_LINK = "Xf01UD0C7526" | ||
POSITION = "Xf01UD0AM3S6" | ||
GENERATION = "Xf02CN9EEQCD" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
team.profile.get
API 를 통해 알아낸 값이며, 운영팀에서 해당 필드들을 삭제하기 전까지 변하지 않는 값들이므로 enum 으로 박아놓음
github_id: str | None = Field( | ||
None, validation_alias=AliasPath("fields", CustomFieldId.GITHUB_LINK, "value") | ||
) | ||
position: str | None = Field( | ||
None, validation_alias=AliasPath("fields", CustomFieldId.POSITION, "value") | ||
) | ||
generation: str | None = Field( | ||
None, validation_alias=AliasPath("fields", CustomFieldId.GENERATION, "value") | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
커스텀 필드이지만 fields
로 묶여있을 이유가 없다고 판단되어 Profile 클래스에 포함되도록 평탄화
result = urlparse(value) | ||
assert result.scheme == "https", "Invalid URL scheme" | ||
assert result.netloc in ["github.com", "www.github.com"], "Invalid URL netloc" | ||
return str(result.path).split("/")[1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
사용자가 입력한 깃헙 링크가 https://github.com/minkyu97 과 같은 형태일 것으로 가정
|
||
return profile | ||
|
||
async def call_api_with_retry( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
slack api 는 사용량 제한이 있어서 꽤 높은 확률로 실패할 수 있음
그 경우 정해진 retry 횟수만큼 10초 기다렸다가 재시도를 반복하는 로직 추가
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏👏
No description provided.