|
618 | 618 | NoopMessageRepository, |
619 | 619 | ) |
620 | 620 | from airbyte_cdk.sources.message.repository import StateFilteringMessageRepository |
621 | | -from airbyte_cdk.sources.streams import NO_CURSOR_STATE_KEY |
622 | 621 | from airbyte_cdk.sources.streams.call_rate import ( |
623 | 622 | APIBudget, |
624 | 623 | FixedWindowCallRatePolicy, |
@@ -3595,50 +3594,53 @@ def create_state_delegating_stream( |
3595 | 3594 | or model.name in self._stream_name_to_configured_stream |
3596 | 3595 | ) |
3597 | 3596 | if model.api_retention_period and stream_is_in_catalog: |
| 3597 | + full_refresh_stream: DefaultStream = self._create_component_from_model( |
| 3598 | + model.full_refresh_stream, config=config, **kwargs |
| 3599 | + ) # type: ignore[assignment] |
3598 | 3600 | if self._is_cursor_older_than_retention_period( |
3599 | 3601 | stream_state, |
| 3602 | + full_refresh_stream.cursor, |
3600 | 3603 | incremental_stream.cursor, |
3601 | 3604 | model.api_retention_period, |
3602 | 3605 | model.name, |
3603 | 3606 | ): |
3604 | | - # Clear state BEFORE constructing the full_refresh_stream so that |
3605 | | - # its cursor starts from start_date instead of the stale cursor. |
3606 | 3607 | self._connector_state_manager.update_state_for_stream(model.name, None, {}) |
3607 | 3608 | state_message = self._connector_state_manager.create_state_message(model.name, None) |
3608 | 3609 | self._message_repository.emit_message(state_message) |
3609 | | - return self._create_component_from_model( # type: ignore[no-any-return] |
3610 | | - model.full_refresh_stream, config=config, **kwargs |
3611 | | - ) |
| 3610 | + return full_refresh_stream |
3612 | 3611 |
|
3613 | 3612 | return incremental_stream |
3614 | 3613 |
|
3615 | 3614 | @staticmethod |
3616 | 3615 | def _is_cursor_older_than_retention_period( |
3617 | 3616 | stream_state: Mapping[str, Any], |
| 3617 | + full_refresh_cursor: Cursor, |
3618 | 3618 | incremental_cursor: Cursor, |
3619 | 3619 | api_retention_period: str, |
3620 | 3620 | stream_name: str, |
3621 | 3621 | ) -> bool: |
3622 | 3622 | """Check if the cursor value in the state is older than the API's retention period. |
3623 | 3623 |
|
3624 | | - If the state contains NO_CURSOR_STATE_KEY, the previous sync was a completed |
3625 | | - full refresh and the cursor is considered current — returns False. |
3626 | | -
|
3627 | | - Otherwise, uses the incremental cursor to parse the datetime from state. |
| 3624 | + Checks cursors in sequence: full refresh cursor first, then incremental cursor. |
| 3625 | + FinalStateCursor returns now() for completed full refresh state (NO_CURSOR_STATE_KEY), |
| 3626 | + which is always within retention, so we use incremental. For other states, it returns |
| 3627 | + None and we fall back to checking the incremental cursor. |
3628 | 3628 |
|
3629 | 3629 | Returns True if the cursor is older than the retention period (should use full refresh). |
3630 | 3630 | Returns False if the cursor is within the retention period (safe to use incremental). |
3631 | 3631 | """ |
3632 | | - if stream_state.get(NO_CURSOR_STATE_KEY): |
3633 | | - return False |
3634 | | - |
3635 | 3632 | retention_duration = parse_duration(api_retention_period) |
3636 | 3633 | retention_cutoff = datetime.datetime.now(datetime.timezone.utc) - retention_duration |
3637 | 3634 |
|
3638 | | - cursor_datetime = incremental_cursor.get_cursor_datetime_from_state(stream_state) |
| 3635 | + # Check full refresh cursor first |
| 3636 | + cursor_datetime = full_refresh_cursor.get_cursor_datetime_from_state(stream_state) |
| 3637 | + |
| 3638 | + # If full refresh cursor returns None, check incremental cursor |
| 3639 | + if cursor_datetime is None: |
| 3640 | + cursor_datetime = incremental_cursor.get_cursor_datetime_from_state(stream_state) |
3639 | 3641 |
|
3640 | 3642 | if cursor_datetime is None: |
3641 | | - # Cursor could not parse the state - fall back to full refresh to be safe |
| 3643 | + # Neither cursor could parse the state - fall back to full refresh to be safe |
3642 | 3644 | return True |
3643 | 3645 |
|
3644 | 3646 | if cursor_datetime < retention_cutoff: |
|
0 commit comments