Skip to content

Commit e3ba9da

Browse files
sakshamg1304rohitesh-wingify
authored andcommitted
feat: Added support for events batching
1 parent 4439408 commit e3ba9da

File tree

18 files changed

+546
-133
lines changed

18 files changed

+546
-133
lines changed

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
aiohttp>=3.8.4
21
murmurhash==1.0.10
32
requests>=2.27.1
43
jsonschema>=3.2.0

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def run(self):
121121

122122
setup(
123123
name="vwo-fme-python-sdk",
124-
version="1.8.0",
124+
version="1.9.0",
125125
description="VWO Feature Management and Experimentation SDK for Python",
126126
long_description=long_description,
127127
long_description_content_type="text/markdown",

vwo/api/set_attribute_api.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,13 @@ def create_and_send_impression_for_attribute(
5151
ip_address=context.get_ip_address(),
5252
)
5353

54-
# Send the constructed properties and payload as a POST request
55-
send_post_api_request(properties, payload)
54+
from vwo.vwo_client import VWOClient
55+
vwo_instance = VWOClient.get_instance()
56+
57+
# Check if batch events are enabled
58+
if vwo_instance.batch_event_queue is not None:
59+
# Enqueue the event to the batch queue
60+
vwo_instance.batch_event_queue.enqueue(payload)
61+
else:
62+
# Send the event immediately if batch events are not enabled
63+
send_post_api_request(properties, payload)

vwo/api/track_api.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,13 @@ def create_and_send_impression_for_track(
9393
ip_address=context.get_ip_address(),
9494
)
9595

96-
# Send the constructed properties and payload as a POST request
97-
send_post_api_request(properties, payload)
96+
from vwo.vwo_client import VWOClient
97+
vwo_instance = VWOClient.get_instance()
98+
99+
# Check if batch events are enabled
100+
if vwo_instance.batch_event_queue is not None:
101+
# Enqueue the event to the batch queue
102+
vwo_instance.batch_event_queue.enqueue(payload)
103+
else:
104+
# Send the event immediately if batch events are not enabled
105+
send_post_api_request(properties, payload)

vwo/constants/Constants.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Constants:
1717
# TODO: read from setup.py
1818
package_file = {
1919
"name": "vwo-fme-python-sdk",
20-
"version": "1.8.0"
20+
"version": "1.9.0"
2121
}
2222

2323
# Constants
@@ -56,3 +56,6 @@ class Constants:
5656
RANDOM_ALGO = 1
5757

5858
VWO_META_MEG_KEY = "_vwo_meta_meg_"
59+
60+
THREAD_POOL_MAX_WORKERS = 5
61+
SHOULD_USE_THREADING = True

vwo/enums/url_enum.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class UrlEnum(Enum):
2020
BASE_URL = "dev.visualwebsiteoptimizer.com"
2121
SETTINGS_URL = "/server-side/settings"
2222
# WEBHOOK_SETTINGS_URL = '/server-side/pull'
23-
# BATCH_EVENTS = '/server-side/batch-events'
24-
EVENTS = "/events/t"
25-
ATTRIBUTE_CHECK = "/check-attribute"
26-
GET_USER_DATA = "/get-user-details"
23+
EVENTS = '/events/t'
24+
ATTRIBUTE_CHECK = '/check-attribute'
25+
GET_USER_DATA = '/get-user-details'
26+
BATCH_EVENTS = '/server-side/batch-events-v2'

vwo/models/batch_event_data.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Copyright 2024 Wingify Software Pvt. Ltd.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
class BatchEventData:
17+
def __init__(self, events_per_request: int = 100, request_time_interval: int = 600, flush_callback=None):
18+
"""
19+
Initialize the BatchEventData model with optional parameters.
20+
21+
:param events_per_request: The number of events to send per batch (default is 100).
22+
:param request_time_interval: The time interval (in seconds) between batch requests (default is 600 seconds).
23+
"""
24+
self.events_per_request = events_per_request # Default value: 100
25+
self.request_time_interval = request_time_interval # Default value: 600
26+
self.flush_callback = flush_callback
27+
28+
def get_events_per_request(self) -> int:
29+
"""
30+
Get the number of events to send per batch.
31+
"""
32+
return self.events_per_request
33+
34+
def set_events_per_request(self, events_per_request: int) -> None:
35+
"""
36+
Set the number of events to send per batch.
37+
38+
:param events_per_request: The number of events to send per batch.
39+
"""
40+
self.events_per_request = events_per_request
41+
42+
def get_request_time_interval(self) -> int:
43+
"""
44+
Get the time interval (in seconds) between batch requests.
45+
"""
46+
return self.request_time_interval
47+
48+
def set_request_time_interval(self, request_time_interval: int) -> None:
49+
"""
50+
Set the time interval (in seconds) between batch requests.
51+
52+
:param request_time_interval: The time interval between batch requests in seconds.
53+
"""
54+
self.request_time_interval = request_time_interval
55+
56+
def get_flush_callback(self):
57+
"""
58+
Get the flush callback function.
59+
"""
60+
return self.flush_callback
61+
62+
def set_flush_callback(self, flush_callback: None):
63+
"""
64+
Set the flush callback function.
65+
66+
:param flush_callback: The callback function to be set.
67+
"""
68+
self.flush_callback = flush_callback

vwo/models/vwo_options_model.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from typing import Dict
1717

18-
18+
from vwo.models.batch_event_data import BatchEventData
1919
class VWOOptionsModel:
2020
def __init__(self, options: Dict):
2121
"""
@@ -35,6 +35,17 @@ def __init__(self, options: Dict):
3535
self.network = options.get("network", None)
3636
self.vwoBuilder = options.get("vwoBuilder", None)
3737

38+
# Initialize BatchEventData
39+
batch_event_data = options.get('batch_event_data', None)
40+
if batch_event_data:
41+
self.batchEventData = BatchEventData(
42+
events_per_request=batch_event_data.get('events_per_request'),
43+
request_time_interval=batch_event_data.get('request_time_interval'),
44+
flush_callback=batch_event_data.get('flush_callback', None)
45+
)
46+
else:
47+
self.batchEventData = None
48+
3849
def get_account_id(self) -> str:
3950
"""
4051
Get the account ID.
@@ -122,3 +133,11 @@ def get_vwo_builder(self):
122133
:return: The VWO builder instance.
123134
"""
124135
return self.vwoBuilder
136+
137+
def get_batch_event_data(self):
138+
"""
139+
Get the batch event data.
140+
141+
:return: The BatchEventData instance.
142+
"""
143+
return self.batchEventData

vwo/packages/network_layer/manager/network_manager.py

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,25 @@
1818
from ..models.response_model import ResponseModel
1919
from ..handlers.request_handler import RequestHandler
2020
from ..client.network_client import NetworkClient
21-
import aiohttp
2221
from ...logger.core.log_manager import LogManager
2322
from ....utils.log_message_util import error_messages
23+
from concurrent.futures import ThreadPoolExecutor
24+
from typing import Callable, Dict, Any
25+
from ....constants.Constants import Constants
2426

2527

2628
class NetworkManager:
2729
_instance = None
2830

29-
def __init__(self):
31+
def __init__(self, threading: Dict[str, Any] = None):
3032
self.client = None
3133
self.config = None
34+
self.should_use_threading = threading.get(
35+
"enabled", Constants.SHOULD_USE_THREADING
36+
)
37+
self.thread_pool_max_workers = threading.get(
38+
"max_workers", Constants.THREAD_POOL_MAX_WORKERS
39+
)
3240

3341
def set_config(self, config: GlobalRequestModel):
3442
self.config = config
@@ -41,9 +49,9 @@ def attach_client(self):
4149
self.config = GlobalRequestModel()
4250

4351
@classmethod
44-
def get_instance(cls) -> "NetworkManager":
52+
def get_instance(cls, threading: Dict[str, Any] = None) -> "NetworkManager":
4553
if cls._instance is None:
46-
cls._instance = cls()
54+
cls._instance = cls(threading)
4755
return cls._instance
4856

4957
def create_request(self, request: RequestModel) -> RequestModel:
@@ -65,21 +73,7 @@ def post(self, request: RequestModel) -> ResponseModel:
6573
return response
6674
return self.client.post(request_model)
6775

68-
async def post_async(self, request: RequestModel):
69-
try:
70-
options = request.get_options()
71-
async with aiohttp.ClientSession() as session:
72-
async with session.post(
73-
options["url"],
74-
json=options.get("json"),
75-
headers=options.get("headers"),
76-
timeout=options.get("timeout"),
77-
) as response:
78-
return response.status
79-
except Exception as err:
80-
LogManager.get_instance().error(
81-
error_messages.get("NETWORK_CALL_FAILED").format(
82-
method="POST",
83-
err=err,
84-
)
85-
)
76+
# Generic function to handle background task execution with ThreadPoolExecutor
77+
def execute_in_background(self, func: Callable):
78+
executor = ThreadPoolExecutor(max_workers=self.thread_pool_max_workers)
79+
executor.submit(func)

vwo/resources/debug-messages.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010

1111
"IMPRESSION_FOR_TRACK_USER": "Impression built for vwo_variationShown(VWO standard event for tracking user) event haivng Account ID:{accountId}, User ID:{userId}, and experiment ID:{campaignId}",
1212
"IMPRESSION_FOR_TRACK_GOAL": "Impression built for event:{eventName} event having Account ID:{accountId}, and user ID:{userId}",
13-
"IMPRESSION_FOR_SYNC_VISITOR_PROP": "Impression built for {eventName}(VWO internal event) event for Account ID:{accountId}, and user ID:{userId}"
13+
"IMPRESSION_FOR_SYNC_VISITOR_PROP": "Impression built for {eventName}(VWO internal event) event for Account ID:{accountId}, and user ID:{userId}",
14+
"BATCHING_INITIALIZED": "BATCHING_INITIALIZED"
1415
}

0 commit comments

Comments
 (0)