-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathevent_client.py
More file actions
95 lines (83 loc) · 3.28 KB
/
Copy pathevent_client.py
File metadata and controls
95 lines (83 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import json
import logging
import time
from typing import Optional, List
import requests
from devcycle_python_sdk.api.backoff import exponential_backoff
from devcycle_python_sdk.options import DevCycleLocalOptions
from devcycle_python_sdk.exceptions import (
APIClientError,
NotFoundError,
APIClientUnauthorizedError,
)
from devcycle_python_sdk.models.event import UserEventsBatchRecord
from devcycle_python_sdk.util.strings import slash_join
logger = logging.getLogger(__name__)
class EventAPIClient:
def __init__(self, sdk_key: str, options: DevCycleLocalOptions):
self.options = options
self.session = requests.Session()
self.session.headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": sdk_key,
}
self.session.max_redirects = 0
self.max_batch_retries = 0 # we don't retry events batches
self.batch_url = slash_join(self.options.events_api_uri, "v1/events/batch")
def publish_events(self, batch: List[UserEventsBatchRecord]) -> str:
"""
Attempts to send a batch of events to the server
"""
retries_remaining = self.max_batch_retries + 1
timeout = self.options.event_request_timeout_ms
payload_json = json.dumps(
{
"batch": [record.to_json() for record in batch],
}
)
attempts = 1
while retries_remaining > 0:
request_error: Optional[Exception] = None
try:
res: requests.Response = self.session.request(
"POST",
self.batch_url,
params={},
timeout=timeout,
data=payload_json,
)
if res.status_code == 401 or res.status_code == 403:
# Not a retryable error
raise APIClientUnauthorizedError("Invalid SDK Key")
elif res.status_code == 404:
# Not a retryable error - bad URL
raise NotFoundError(self.batch_url)
elif 400 <= res.status_code < 500:
# Not a retryable error
raise APIClientError(
f"Bad request: HTTP {res.status_code} - {res.text}"
)
elif res.status_code >= 500:
# Retryable error
request_error = APIClientError(
f"Server error: HTTP {res.status_code}"
)
except requests.exceptions.RequestException as e:
request_error = e
if not request_error:
break
logger.debug(
f"DevCycle event batch request failed (attempt {attempts}): {request_error}"
)
retries_remaining -= 1
if retries_remaining:
retry_delay = exponential_backoff(
attempts, self.options.event_retry_delay_ms / 1000.0
)
time.sleep(retry_delay)
attempts += 1
continue
raise APIClientError(message="Retries exceeded", cause=request_error)
data: dict = res.json()
return data.get("message", None)