Skip to content
Open
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
18 changes: 17 additions & 1 deletion tap_github/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,23 @@ def get_records(self, context: Context | None) -> Iterable[dict[str, Any]]:
if context is not None and "org" in context:
self.authenticator.set_organization(context["org"])

yield from super().get_records(context)
try:
yield from super().get_records(context)
except Exception as exc:
# singer_sdk's own Stream.sync() catch-all only logs "an unhandled
# error occurred while syncing '<stream>'" with no detail on why.
# Surface the real cause here before it propagates -
# FatalAPIError/RetriableAPIError already carry a rich message
# (HTTP status, GitHub-Request-Id, ...) that would otherwise be
# lost.
self.logger.error(
"%s failed for context=%s: %s: %s",
self.name,
context,
type(exc).__name__,
exc,
)
raise

def _throttle_before_request(self) -> None:
"""Sleep if we're currently backing off from a secondary rate limit."""
Expand Down
12 changes: 10 additions & 2 deletions tap_github/repository_streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,12 @@ def _get_records_round_robin(self, context: Context) -> Iterable[dict[str, Any]]

all_records = list(super().get_records(context))
if not all_records:
self.logger.info(f"[{self.name}:{partition_label}] round-robin summary: 0 repos returned by the API.")
# warning, not info: prod runs at warning level, and this
# summary is the only per-run signal of enumeration progress.
self.logger.warning(
f"[{self.name}:{partition_label}] round-robin summary: "
"0 repos returned by the API."
)
return

all_records.sort(key=lambda record: record["id"])
Expand Down Expand Up @@ -342,7 +347,10 @@ def _get_records_round_robin(self, context: Context) -> Iterable[dict[str, Any]]
self._write_state_message()
finally:
full_lap = processed >= len(ordered_records)
self.logger.info(
# warning, not info: prod runs at warning level, and this is the
# only per-run signal of enumeration progress - without it there
# is no visibility into how far a run got before crashing.
self.logger.warning(
f"[{self.name}:{partition_label}] round-robin summary: "
f"processed {processed}/{len(ordered_records)} repos in "
f"{time.monotonic() - started_at:.1f}s "
Expand Down