|
14 | 14 | AirbyteStreamStatus,
|
15 | 15 | ConfiguredAirbyteCatalog,
|
16 | 16 | ConfiguredAirbyteStream,
|
| 17 | + FailureType, |
17 | 18 | Status,
|
| 19 | + StreamDescriptor, |
18 | 20 | SyncMode,
|
19 | 21 | )
|
20 | 22 | from airbyte_cdk.models import Type as MessageType
|
|
27 | 29 | from airbyte_cdk.sources.utils.record_helper import stream_data_to_airbyte_message
|
28 | 30 | from airbyte_cdk.sources.utils.schema_helpers import InternalConfig, split_config
|
29 | 31 | from airbyte_cdk.sources.utils.slice_logger import DebugSliceLogger, SliceLogger
|
| 32 | +from airbyte_cdk.utils.airbyte_secrets_utils import filter_secrets |
30 | 33 | from airbyte_cdk.utils.event_timing import create_timer
|
31 | 34 | from airbyte_cdk.utils.stream_status_utils import as_airbyte_message as stream_status_as_airbyte_message
|
32 | 35 | from airbyte_cdk.utils.traced_exception import AirbyteTracedException
|
@@ -133,27 +136,45 @@ def read(
|
133 | 136 | logger.info(f"Marking stream {configured_stream.stream.name} as STOPPED")
|
134 | 137 | yield stream_status_as_airbyte_message(configured_stream.stream, AirbyteStreamStatus.COMPLETE)
|
135 | 138 | except AirbyteTracedException as e:
|
| 139 | + logger.exception(f"Encountered an exception while reading stream {configured_stream.stream.name}") |
| 140 | + logger.info(f"Marking stream {configured_stream.stream.name} as STOPPED") |
136 | 141 | yield stream_status_as_airbyte_message(configured_stream.stream, AirbyteStreamStatus.INCOMPLETE)
|
137 |
| - if self.continue_sync_on_stream_failure: |
138 |
| - stream_name_to_exception[stream_instance.name] = e |
139 |
| - else: |
140 |
| - raise e |
| 142 | + yield e.as_sanitized_airbyte_message(stream_descriptor=StreamDescriptor(name=configured_stream.stream.name)) |
| 143 | + stream_name_to_exception[stream_instance.name] = e |
| 144 | + if self.stop_sync_on_stream_failure: |
| 145 | + logger.info( |
| 146 | + f"Stopping sync on error from stream {configured_stream.stream.name} because {self.name} does not support continuing syncs on error." |
| 147 | + ) |
| 148 | + break |
141 | 149 | except Exception as e:
|
142 | 150 | yield from self._emit_queued_messages()
|
143 | 151 | logger.exception(f"Encountered an exception while reading stream {configured_stream.stream.name}")
|
144 | 152 | logger.info(f"Marking stream {configured_stream.stream.name} as STOPPED")
|
145 | 153 | yield stream_status_as_airbyte_message(configured_stream.stream, AirbyteStreamStatus.INCOMPLETE)
|
146 | 154 | display_message = stream_instance.get_error_display_message(e)
|
147 | 155 | if display_message:
|
148 |
| - raise AirbyteTracedException.from_exception(e, message=display_message) from e |
149 |
| - raise e |
| 156 | + traced_exception = AirbyteTracedException.from_exception(e, message=display_message) |
| 157 | + else: |
| 158 | + traced_exception = AirbyteTracedException.from_exception(e) |
| 159 | + yield traced_exception.as_sanitized_airbyte_message( |
| 160 | + stream_descriptor=StreamDescriptor(name=configured_stream.stream.name) |
| 161 | + ) |
| 162 | + stream_name_to_exception[stream_instance.name] = traced_exception |
| 163 | + if self.stop_sync_on_stream_failure: |
| 164 | + logger.info(f"{self.name} does not support continuing syncs on error from stream {configured_stream.stream.name}") |
| 165 | + break |
150 | 166 | finally:
|
151 | 167 | timer.finish_event()
|
152 | 168 | logger.info(f"Finished syncing {configured_stream.stream.name}")
|
153 | 169 | logger.info(timer.report())
|
154 | 170 |
|
155 |
| - if self.continue_sync_on_stream_failure and len(stream_name_to_exception) > 0: |
156 |
| - raise AirbyteTracedException(message=self._generate_failed_streams_error_message(stream_name_to_exception)) |
| 171 | + if len(stream_name_to_exception) > 0: |
| 172 | + error_message = self._generate_failed_streams_error_message(stream_name_to_exception) |
| 173 | + logger.info(error_message) |
| 174 | + # We still raise at least one exception when a stream raises an exception because the platform currently relies |
| 175 | + # on a non-zero exit code to determine if a sync attempt has failed. We also raise the exception as a config_error |
| 176 | + # type because this combined error isn't actionable, but rather the previously emitted individual errors. |
| 177 | + raise AirbyteTracedException(message=error_message, failure_type=FailureType.config_error) |
157 | 178 | logger.info(f"Finished syncing {self.name}")
|
158 | 179 |
|
159 | 180 | @property
|
@@ -282,17 +303,17 @@ def message_repository(self) -> Union[None, MessageRepository]:
|
282 | 303 | return _default_message_repository
|
283 | 304 |
|
284 | 305 | @property
|
285 |
| - def continue_sync_on_stream_failure(self) -> bool: |
| 306 | + def stop_sync_on_stream_failure(self) -> bool: |
286 | 307 | """
|
287 | 308 | WARNING: This function is in-development which means it is subject to change. Use at your own risk.
|
288 | 309 |
|
289 |
| - By default, a source should raise an exception and stop the sync when it encounters an error while syncing a stream. This |
290 |
| - method can be overridden on a per-source basis so that a source will continue syncing streams other streams even if an |
291 |
| - exception is raised for a stream. |
| 310 | + By default, when a source encounters an exception while syncing a stream, it will emit an error trace message and then |
| 311 | + continue syncing the next stream. This can be overwritten on a per-source basis so that the source will stop the sync |
| 312 | + on the first error seen and emit a single error trace message for that stream. |
292 | 313 | """
|
293 | 314 | return False
|
294 | 315 |
|
295 | 316 | @staticmethod
|
296 | 317 | def _generate_failed_streams_error_message(stream_failures: Mapping[str, AirbyteTracedException]) -> str:
|
297 |
| - failures = ", ".join([f"{stream}: {exception.__repr__()}" for stream, exception in stream_failures.items()]) |
| 318 | + failures = ", ".join([f"{stream}: {filter_secrets(exception.__repr__())}" for stream, exception in stream_failures.items()]) |
298 | 319 | return f"During the sync, the following streams did not sync successfully: {failures}"
|
0 commit comments