9
9
10
10
import pendulum
11
11
import requests
12
- from airbyte_cdk . models import FailureType
12
+ from airbyte_cdk import BackoffStrategy
13
13
from airbyte_cdk .sources .streams .http import HttpStream
14
- from airbyte_cdk .utils import AirbyteTracedException
14
+ from airbyte_cdk .sources . streams . http . error_handlers import ErrorHandler
15
15
from pendulum import Date
16
16
from requests .auth import AuthBase
17
+ from source_mixpanel .backoff_strategy import MixpanelStreamBackoffStrategy
18
+ from source_mixpanel .errors_handlers import MixpanelStreamErrorHandler
17
19
from source_mixpanel .utils import fix_date_time
18
20
19
21
@@ -69,7 +71,6 @@ def __init__(
69
71
self .region = region
70
72
self .project_timezone = project_timezone
71
73
self .project_id = project_id
72
- self .retries = 0
73
74
self ._reqs_per_hour_limit = reqs_per_hour_limit
74
75
super ().__init__ (authenticator = authenticator )
75
76
@@ -110,42 +111,18 @@ def parse_response(
110
111
self .logger .info (f"Sleep for { 3600 / self .reqs_per_hour_limit } seconds to match API limitations after reading from { self .name } " )
111
112
time .sleep (3600 / self .reqs_per_hour_limit )
112
113
113
- @property
114
- def max_retries (self ) -> Union [int , None ]:
115
- # we want to limit the max sleeping time by 2^3 * 60 = 8 minutes
116
- return 3
114
+ def get_backoff_strategy (self ) -> Optional [Union [BackoffStrategy , List [BackoffStrategy ]]]:
115
+ return MixpanelStreamBackoffStrategy (stream = self )
117
116
118
- def backoff_time (self , response : requests .Response ) -> float :
119
- """
120
- Some API endpoints do not return "Retry-After" header.
121
- """
122
-
123
- retry_after = response .headers .get ("Retry-After" )
124
- if retry_after :
125
- self .logger .debug (f"API responded with `Retry-After` header: { retry_after } " )
126
- return float (retry_after )
127
-
128
- self .retries += 1
129
- return 2 ** self .retries * 60
130
-
131
- def should_retry (self , response : requests .Response ) -> bool :
132
- if response .status_code == 402 :
133
- self .logger .warning (f"Unable to perform a request. Payment Required: { response .json ()['error' ]} " )
134
- return False
135
- if response .status_code == 400 and "Unable to authenticate request" in response .text :
136
- message = (
137
- f"Your credentials might have expired. Please update your config with valid credentials."
138
- f" See more details: { response .text } "
139
- )
140
- raise AirbyteTracedException (message = message , internal_message = message , failure_type = FailureType .config_error )
141
- return super ().should_retry (response )
117
+ def get_error_handler (self ) -> Optional [ErrorHandler ]:
118
+ return MixpanelStreamErrorHandler (logger = self .logger )
142
119
143
120
def get_stream_params (self ) -> Mapping [str , Any ]:
144
121
"""
145
122
Fetch required parameters in a given stream. Used to create sub-streams
146
123
"""
147
124
params = {
148
- "authenticator" : self ._session .auth ,
125
+ "authenticator" : self ._http_client . _session .auth ,
149
126
"region" : self .region ,
150
127
"project_timezone" : self .project_timezone ,
151
128
"reqs_per_hour_limit" : self .reqs_per_hour_limit ,
@@ -168,18 +145,6 @@ def request_params(
168
145
class DateSlicesMixin :
169
146
raise_on_http_errors = True
170
147
171
- def should_retry (self , response : requests .Response ) -> bool :
172
- if response .status_code == requests .codes .bad_request :
173
- if "to_date cannot be later than today" in response .text :
174
- self ._timezone_mismatch = True
175
- self .logger .warning (
176
- "Your project timezone must be misconfigured. Please set it to the one defined in your Mixpanel project settings. "
177
- "Stopping current stream sync."
178
- )
179
- setattr (self , "raise_on_http_errors" , False )
180
- return False
181
- return super ().should_retry (response )
182
-
183
148
def __init__ (self , * args , ** kwargs ):
184
149
super ().__init__ (* args , ** kwargs )
185
150
self ._timezone_mismatch = False
0 commit comments