Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
9.1.0 (Jul 15, 2021)
- Added Cache-Control header for on-demand requests to sdk-server.
- Updated the synchronization flow to be more reliable in the event of an edge case generating delay in cache purge propagation, keeping the SDK cache properly synced.

9.0.0 (May 3, 2021)
- BREAKING CHANGE: Removed splitSdkMachineIp and splitSdkMachineName configs.
- BREAKING CHANGE: Deprecated `redisCharset` config.
Expand Down
28 changes: 0 additions & 28 deletions splitio/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,3 @@ def __init__(self, custom_message, status_code=None):
def status_code(self):
"""Return HTTP status code."""
return self._status_code


def headers_from_metadata(sdk_metadata, client_key=None):
"""
Generate a dict with headers required by data-recording API endpoints.

:param sdk_metadata: SDK Metadata object, generated at sdk initialization time.
:type sdk_metadata: splitio.client.util.SdkMetadata

:param client_key: client key.
:type client_key: str

:return: A dictionary with headers.
:rtype: dict
"""

metadata = {
'SplitSDKVersion': sdk_metadata.sdk_version,
'SplitSDKMachineIP': sdk_metadata.instance_ip,
'SplitSDKMachineName': sdk_metadata.instance_name
} if sdk_metadata.instance_ip != 'NA' and sdk_metadata.instance_ip != 'unknown' else {
'SplitSDKVersion': sdk_metadata.sdk_version,
}

if client_key is not None:
metadata['SplitSDKClientKey'] = client_key

return metadata
3 changes: 2 additions & 1 deletion splitio/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import logging
import json

from splitio.api import APIException, headers_from_metadata
from splitio.api import APIException
from splitio.api.commons import headers_from_metadata
from splitio.api.client import HttpClientException
from splitio.models.token import from_raw

Expand Down
95 changes: 95 additions & 0 deletions splitio/api/commons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""Commons module."""


_CACHE_CONTROL = 'Cache-Control'
_CACHE_CONTROL_NO_CACHE = 'no-cache'


def headers_from_metadata(sdk_metadata, client_key=None):
"""
Generate a dict with headers required by data-recording API endpoints.

:param sdk_metadata: SDK Metadata object, generated at sdk initialization time.
:type sdk_metadata: splitio.client.util.SdkMetadata

:param client_key: client key.
:type client_key: str

:return: A dictionary with headers.
:rtype: dict
"""

metadata = {
'SplitSDKVersion': sdk_metadata.sdk_version,
'SplitSDKMachineIP': sdk_metadata.instance_ip,
'SplitSDKMachineName': sdk_metadata.instance_name
} if sdk_metadata.instance_ip != 'NA' and sdk_metadata.instance_ip != 'unknown' else {
'SplitSDKVersion': sdk_metadata.sdk_version,
}

if client_key is not None:
metadata['SplitSDKClientKey'] = client_key

return metadata


class FetchOptions(object):
"""Fetch Options object."""

def __init__(self, cache_control_headers=False, change_number=None):
"""
Class constructor.

:param cache_control_headers: Flag for Cache-Control header
:type cache_control_headers: bool

:param change_number: ChangeNumber to use for bypassing CDN in request.
:type change_number: int
"""
self._cache_control_headers = cache_control_headers
self._change_number = change_number

@property
def cache_control_headers(self):
"""Return cache control headers."""
return self._cache_control_headers

@property
def change_number(self):
"""Return change number."""
return self._change_number

def __eq__(self, other):
"""Match between other options."""
if self._cache_control_headers != other._cache_control_headers:
return False
if self._change_number != other._change_number:
return False
return True


def build_fetch(change_number, fetch_options, metadata):
"""
Build fetch with new flags if that is the case.

:param change_number: Last known timestamp of definition.
:type change_number: int

:param fetch_options: Fetch options for getting definitions.
:type fetch_options: splitio.api.commons.FetchOptions

:param metadata: Metadata Headers.
:type metadata: dict

:return: Objects for fetch
:rtype: dict, dict
"""
query = {'since': change_number}
extra_headers = metadata
if fetch_options is None:
return query, extra_headers
if fetch_options.cache_control_headers:
extra_headers[_CACHE_CONTROL] = _CACHE_CONTROL_NO_CACHE
if fetch_options.change_number is not None:
query['till'] = fetch_options.change_number
return query, extra_headers
3 changes: 2 additions & 1 deletion splitio/api/events.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""Events API module."""
import logging

from splitio.api import APIException, headers_from_metadata
from splitio.api import APIException
from splitio.api.client import HttpClientException
from splitio.api.commons import headers_from_metadata


_LOGGER = logging.getLogger(__name__)
Expand Down
3 changes: 2 additions & 1 deletion splitio/api/impressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import logging
from itertools import groupby

from splitio.api import APIException, headers_from_metadata
from splitio.api import APIException
from splitio.api.client import HttpClientException
from splitio.api.commons import headers_from_metadata
from splitio.engine.impressions import ImpressionsMode


Expand Down
16 changes: 11 additions & 5 deletions splitio/api/segments.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import json
import logging

from splitio.api import APIException, headers_from_metadata
from splitio.api import APIException
from splitio.api.commons import headers_from_metadata, build_fetch
from splitio.api.client import HttpClientException


Expand All @@ -29,25 +30,30 @@ def __init__(self, http_client, apikey, sdk_metadata):
self._apikey = apikey
self._metadata = headers_from_metadata(sdk_metadata)

def fetch_segment(self, segment_name, change_number):
def fetch_segment(self, segment_name, change_number, fetch_options):
"""
Fetch splits from backend.

:param segment_name: Name of the segment to fetch changes for.
:type segment_name: str
:param change_number: Last known timestamp of a split modification.

:param change_number: Last known timestamp of a segment modification.
:type change_number: int

:param fetch_options: Fetch options for getting segment definitions.
:type fetch_options: splitio.api.commons.FetchOptions

:return: Json representation of a segmentChange response.
:rtype: dict
"""
try:
query, extra_headers = build_fetch(change_number, fetch_options, self._metadata)
response = self._client.get(
'sdk',
'/segmentChanges/{segment_name}'.format(segment_name=segment_name),
self._apikey,
extra_headers=self._metadata,
query={'since': change_number}
extra_headers=extra_headers,
query=query,
)

if 200 <= response.status_code < 300:
Expand Down
17 changes: 11 additions & 6 deletions splitio/api/splits.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import logging
import json

from splitio.api import APIException, headers_from_metadata
from splitio.api import APIException
from splitio.api.commons import headers_from_metadata, build_fetch
from splitio.api.client import HttpClientException


Expand All @@ -28,23 +29,27 @@ def __init__(self, client, apikey, sdk_metadata):
self._apikey = apikey
self._metadata = headers_from_metadata(sdk_metadata)

def fetch_splits(self, change_number):
def fetch_splits(self, change_number, fetch_options):
"""
Fetch splits from backend.

:param changeNumber: Last known timestamp of a split modification.
:type changeNumber: int
:param change_number: Last known timestamp of a split modification.
:type change_number: int

:param fetch_options: Fetch options for getting split definitions.
:type fetch_options: splitio.api.commons.FetchOptions

:return: Json representation of a splitChanges response.
:rtype: dict
"""
try:
query, extra_headers = build_fetch(change_number, fetch_options, self._metadata)
response = self._client.get(
'sdk',
'/splitChanges',
self._apikey,
extra_headers=self._metadata,
query={'since': change_number}
extra_headers=extra_headers,
query=query,
)
if 200 <= response.status_code < 300:
return json.loads(response.body)
Expand Down
3 changes: 2 additions & 1 deletion splitio/api/telemetry.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Telemetry API Module."""
import logging

from splitio.api import APIException, headers_from_metadata
from splitio.api import APIException
from splitio.api.commons import headers_from_metadata
from splitio.api.client import HttpClientException


Expand Down
3 changes: 2 additions & 1 deletion splitio/client/input_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import math

from splitio.api import APIException
from splitio.api.commons import FetchOptions
from splitio.client.key import Key
from splitio.engine.evaluator import CONTROL

Expand Down Expand Up @@ -458,7 +459,7 @@ def validate_apikey_type(segment_api):
_logger = logging.getLogger('splitio.api.segments')
try:
_logger.addFilter(api_messages_filter) # pylint: disable=protected-access
segment_api.fetch_segment('__SOME_INVALID_SEGMENT__', -1)
segment_api.fetch_segment('__SOME_INVALID_SEGMENT__', -1, FetchOptions())
except APIException as exc:
if exc.status_code == 403:
_LOGGER.error('factory instantiation: you passed a browser type '
Expand Down
2 changes: 1 addition & 1 deletion splitio/push/splitsse.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from enum import Enum
from splitio.push.sse import SSEClient, SSE_EVENT_ERROR
from splitio.util.threadutil import EventGroup
from splitio.api import headers_from_metadata
from splitio.api.commons import headers_from_metadata


_LOGGER = logging.getLogger(__name__)
Expand Down
Loading