|
1 | 1 | import json |
| 2 | +import time |
2 | 3 | from typing import Any, Dict, Iterator, Optional |
3 | 4 |
|
4 | 5 | from pydantic import BaseModel |
@@ -128,22 +129,32 @@ def _handle_send_err(self, err: SlackApiError, channel_name: str): |
128 | 129 | @sleep_and_retry |
129 | 130 | @limits(calls=20, period=ONE_MINUTE) |
130 | 131 | def _iter_channels( |
131 | | - self, cursor: Optional[str] = None, only_public: bool = False |
| 132 | + self, |
| 133 | + cursor: Optional[str] = None, |
| 134 | + only_public: bool = False, |
| 135 | + timeout: float = 300.0, |
132 | 136 | ) -> Iterator[dict]: |
| 137 | + if timeout <= 0: |
| 138 | + raise MessagingIntegrationError("Channel iteration timed out") |
| 139 | + |
| 140 | + call_start = time.time() |
133 | 141 | response = self.client.conversations_list( |
134 | 142 | cursor=cursor, |
135 | 143 | types="public_channel" if only_public else "public_channel,private_channel", |
136 | 144 | exclude_archived=True, |
137 | 145 | limit=1000, |
138 | 146 | ) |
| 147 | + call_duration = time.time() - call_start |
| 148 | + |
139 | 149 | channels = response["channels"] |
140 | 150 | yield from channels |
141 | 151 | response_metadata = response.get("response_metadata") or {} |
142 | 152 | next_cursor = response_metadata.get("next_cursor") |
143 | 153 | if next_cursor: |
144 | 154 | if not isinstance(next_cursor, str): |
145 | 155 | raise ValueError("Next cursor is not a string") |
146 | | - yield from self._iter_channels(next_cursor, only_public) |
| 156 | + timeout_left = timeout - call_duration |
| 157 | + yield from self._iter_channels(next_cursor, only_public, timeout_left) |
147 | 158 |
|
148 | 159 | def _get_channel_id(self, channel_name: str, only_public: bool = False) -> str: |
149 | 160 | for channel in self._iter_channels(only_public=only_public): |
|
0 commit comments