Skip to content
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

[Integration][Gitlab] Add timeout to merge requests #1325

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 45 additions & 6 deletions integrations/gitlab/gitlab_integration/events/hooks/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@
GitlabPortAppConfig,
GitlabMemberSelector,
)
import asyncio
from tenacity import retry, stop_after_attempt, wait_fixed, wait_exponential, retry_if_exception_type


class HookConfig:
TIMEOUT = 120 # seconds
BACKOFF_EXPONENTIAL = 2
BACKOFF_MAX_ATTEMPTS = 5
BACKOFF_MAX_TIME = 60 # seconds
BACKOFF_MIN_TIME = 1 # seconds


class HookHandler(ABC):
Expand Down Expand Up @@ -64,6 +74,15 @@ async def _register_object_with_members(self, kind: str, gitlab_object: RESTObje


class ProjectHandler(HookHandler):
@retry(
wait=wait_exponential(
multiplier=HookConfig.BACKOFF_EXPONENTIAL,
min=HookConfig.BACKOFF_MIN_TIME,
max=HookConfig.BACKOFF_MAX_TIME,
),
retry = retry_if_exception_type(asyncio.TimeoutError),
stop=stop_after_attempt(HookConfig.BACKOFF_MAX_ATTEMPTS),
)
async def on_hook(self, event: str, body: dict[str, Any]) -> None:
logger.info(f"Handling {event}")

Expand All @@ -77,8 +96,15 @@ async def on_hook(self, event: str, body: dict[str, Any]) -> None:
f"Handling hook {event} for project {project.path_with_namespace}"
)
try:
await self._on_hook(body, project)
asyncio.wait_for(
self._on_hook(body, project), timeout=HookConfig.TIMEOUT
)
logger.info(f"Finished handling {event}")
except asyncio.TimeoutError:
logger.error(
f"Timeout while handling hook {event} for project {project.path_with_namespace}"
)
raise
except Exception as e:
logger.error(
f"Error handling hook {event} for project {project.path_with_namespace}. Error: {e}"
Expand All @@ -94,14 +120,27 @@ async def _on_hook(self, body: dict[str, Any], gitlab_project: Project) -> None:


class GroupHandler(HookHandler):
@retry(
retry=retry_if_exception_type(asyncio.TimeoutError),
wait=wait_exponential(
multiplier=HookConfig.BACKOFF_EXPONENTIAL,
min=HookConfig.BACKOFF_MIN_TIME,
max=HookConfig.BACKOFF_MAX_TIME,
),
stop=stop_after_attempt(HookConfig.BACKOFF_MAX_ATTEMPTS),
)
async def on_hook(self, event: str, body: dict[str, Any]) -> None:
logger.info(f"Handling {event}")

group_id = body.get("group_id", body.get("group", {}).get("id"))
group = await self.gitlab_service.get_group(group_id)
await self._on_hook(body, group)
group_path = body.get("full_path", body.get("group_path"))
logger.info(f"Finished handling {event} for group {group_path}")
try:
group_id = body.get("group_id", body.get("group", {}).get("id"))
group = await self.gitlab_service.get_group(group_id)
asyncio.wait_for(self._on_hook(body, group), timeout=HookConfig.TIMEOUT)
group_path = body.get("full_path", body.get("group_path"))
logger.info(f"Finished handling {event} for group {group_path}")
except asyncio.TimeoutError:
logger.error(f"Timeout while handling hook {event} for group {group_path}")
raise

@abstractmethod
async def _on_hook(
Expand Down
Loading
Loading