Skip to content

Commit 3b700b8

Browse files
sakshamg1304rohitesh-wingify
authored andcommitted
feat: getFlag Batching
1 parent e2b2edb commit 3b700b8

File tree

9 files changed

+164
-23
lines changed

9 files changed

+164
-23
lines changed

CHANGELOG.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,19 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [1.14.0] - 2025-01-XX
8+
## [1.15.0] - 2025-12-10
9+
10+
### Added
11+
12+
- Added batch event processing to optimize network calls during GetFlag operations. Multiple impression events are now collected and sent in a single batch request
13+
14+
## [1.14.0] - 2025-11-26
915

1016
### Fixed
1117

1218
- Fixed GET requests (settings calls) to always use cURL instead of sockets for improved reliability.
1319

20+
1421
## [1.13.0] - 2025-10-10
1522

1623
### Added
@@ -263,4 +270,4 @@ $vwoClient->setAlias('userId', 'aliasId');
263270
// set Attribute
264271
$setAttribute = $vwoClient->setAttribute('attribute-name', 'attribute-value', $userContext);
265272

266-
```
273+
```

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vwo/vwo-fme-php-sdk",
33

4-
"version": "1.14.0",
4+
"version": "1.15.0",
55
"keywords": ["vwo", "fme", "sdk"],
66
"license": "Apache-2.0",
77
"authors": [{

src/Api/GetFlag.php

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
use vwo\Utils\ImpressionUtil;
3838
use vwo\Utils\GetFlagResultUtil;
3939
use vwo\Utils\RuleEvaluationUtil;
40+
use vwo\Utils\NetworkUtil;
41+
use vwo\Enums\EventEnum;
42+
use vwo\Services\SettingsService;
4043

4144
class GetFlag
4245
{
@@ -57,6 +60,7 @@ public function get(
5760
$evaluatedFeatureMap = [];
5861
$storageService = new StorageService();
5962
$ruleStatus = [];
63+
$batchPayload = [];
6064

6165
// Get feature object from feature key
6266
$feature = FunctionUtil::getFeatureFromKey($settings, $featureKey);
@@ -155,6 +159,18 @@ public function get(
155159
);
156160

157161
if ($evaluateRuleResult['preSegmentationResult']) {
162+
$payload = $evaluateRuleResult['payload'];
163+
if(!$isDebuggerUsed) {
164+
if(SettingsService::instance()->isGatewayServiceProvided && $payload !== null) {
165+
ImpressionUtil::SendImpressionForVariationShown($settings, $payload, $context);
166+
} else {
167+
//push this payload to the batch payload
168+
if($payload !== null) {
169+
$batchPayload[] = $payload;
170+
}
171+
}
172+
}
173+
158174
$evaluatedFeatureMap[$featureKey] = [
159175
'rolloutId' => $rule->getId(),
160176
'rolloutKey' => $rule->getKey(),
@@ -180,12 +196,24 @@ public function get(
180196
$this->updateIntegrationsDecisionObject($passedRolloutCampaign, $variation, $passedRulesInformation, $decision);
181197

182198
if (!$isDebuggerUsed) {
183-
ImpressionUtil::createAndSendImpressionForVariationShown(
199+
//push this payload to the batch payload
200+
$networkUtil = new NetworkUtil();
201+
$payload = $networkUtil->getTrackUserPayloadData(
184202
$settings,
203+
EventEnum::VWO_VARIATION_SHOWN,
185204
$passedRolloutCampaign->getId(),
186205
$variation->getId(),
187206
$context
188207
);
208+
209+
if(SettingsService::instance()->isGatewayServiceProvided && $payload !== null) {
210+
ImpressionUtil::SendImpressionForVariationShown($settings, $payload, $context);
211+
} else {
212+
//push this payload to the batch payload
213+
if($payload !== null) {
214+
$batchPayload[] = $payload;
215+
}
216+
}
189217
}
190218
}
191219
}
@@ -218,6 +246,14 @@ public function get(
218246
$experimentRulesToEvaluate[] = $rule;
219247
} else {
220248
$isEnabled = true;
249+
$payload = $evaluateRuleResult['payload'];
250+
if(SettingsService::instance()->isGatewayServiceProvided && $payload !== null) {
251+
ImpressionUtil::SendImpressionForVariationShown($settings, $payload, $context);
252+
} else {
253+
if($payload !== null) {
254+
$batchPayload[] = $payload;
255+
}
256+
}
221257
$experimentVariationToReturn = $evaluateRuleResult['whitelistedObject']['variation'];
222258

223259
$passedRulesInformation = array_merge($passedRulesInformation, [
@@ -245,12 +281,23 @@ public function get(
245281
$this->updateIntegrationsDecisionObject($campaign, $variation, $passedRulesInformation, $decision);
246282

247283
if (!$isDebuggerUsed) {
248-
ImpressionUtil::createAndSendImpressionForVariationShown(
284+
// Construct payload data for tracking the user
285+
$networkUtil = new NetworkUtil();
286+
$payload = $networkUtil->getTrackUserPayloadData(
249287
$settings,
288+
EventEnum::VWO_VARIATION_SHOWN,
250289
$campaign->getId(),
251290
$variation->getId(),
252291
$context
253292
);
293+
if(SettingsService::instance()->isGatewayServiceProvided && $payload !== null) {
294+
ImpressionUtil::SendImpressionForVariationShown($settings, $payload, $context);
295+
} else {
296+
//push this payload to the batch payload
297+
if($payload !== null) {
298+
$batchPayload[] = $payload;
299+
}
300+
}
254301
}
255302
}
256303
}
@@ -282,12 +329,23 @@ public function get(
282329
));
283330

284331
if (!$isDebuggerUsed) {
285-
ImpressionUtil::createAndSendImpressionForVariationShown(
332+
// Construct payload data for tracking the user
333+
$networkUtil = new NetworkUtil();
334+
$payload = $networkUtil->getTrackUserPayloadData(
286335
$settings,
336+
EventEnum::VWO_VARIATION_SHOWN,
287337
$feature->getImpactCampaign()->getCampaignId(),
288338
$isEnabled ? 2 : 1,
289339
$context
290340
);
341+
if(SettingsService::instance()->isGatewayServiceProvided && $payload !== null) {
342+
ImpressionUtil::SendImpressionForVariationShown($settings, $payload, $context);
343+
} else {
344+
//push this payload to the batch payload
345+
if($payload !== null) {
346+
$batchPayload[] = $payload;
347+
}
348+
}
291349
}
292350
}
293351

@@ -299,6 +357,10 @@ public function get(
299357
$variablesForEvaluatedFlag = $rolloutVariationToReturn->getVariables();
300358
}
301359

360+
if(!SettingsService::instance()->isGatewayServiceProvided) {
361+
ImpressionUtil::SendImpressionForVariationShownInBatch($batchPayload);
362+
}
363+
302364
return new GetFlagResultUtil($isEnabled, $variablesForEvaluatedFlag, $ruleStatus);
303365
}
304366

src/Constants/Constants.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class Constants {
4040
const DEFAULT_EVENTS_PER_REQUEST = 100;
4141
const SDK_NAME = 'vwo-fme-php-sdk';
4242

43-
const SDK_VERSION = '1.14.0';
43+
const SDK_VERSION = '1.15.0';
4444
const AP = 'server';
4545

4646
const SETTINGS = 'settings';

src/Enums/HeadersEnum.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@
2121
class HeadersEnum {
2222
const USER_AGENT = 'X-Device-User-Agent';
2323
const IP = 'VWO-X-Forwarded-For';
24+
const AUTHORIZATION = 'Authorization';
2425
}
2526
?>

src/Enums/UrlEnum.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class UrlEnum {
2525
const TRACK_USER = '/server-side/track-user';
2626
const TRACK_GOAL = '/server-side/track-goal';
2727
const PUSH = '/server-side/push';
28-
const BATCH_EVENTS = '/server-side/batch-events';
28+
const BATCH_EVENTS = '/server-side/batch-events-v2';
2929
const EVENTS = '/events/t';
3030
const ATTRIBUTE_CHECK = '/check-attribute';
3131
const GET_USER_DATA = '/get-user-details';

src/Utils/ImpressionUtil.php

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,19 @@
2222
use vwo\Enums\EventEnum;
2323
use vwo\Utils\NetworkUtil;
2424
use vwo\Models\User\ContextModel;
25+
use vwo\Enums\HeadersEnum;
26+
use vwo\Services\SettingsService;
27+
use vwo\Services\UrlService;
28+
use vwo\Enums\UrlEnum;
29+
use vwo\Packages\NetworkLayer\Manager\NetworkManager;
30+
use vwo\Packages\NetworkLayer\Models\RequestModel;
31+
use vwo\Packages\Logger\Core\LogManager;
2532

2633
class ImpressionUtil
2734
{
35+
private $accountId;
36+
37+
2838
/**
2939
* Creates and sends an impression for a variation shown event.
3040
* This function constructs the necessary properties and payload for the event
@@ -35,10 +45,9 @@ class ImpressionUtil
3545
* @param int $variationId - The ID of the variation shown to the user.
3646
* @param ContextModel $context - The user context model containing user-specific data.
3747
*/
38-
public static function createAndSendImpressionForVariationShown(
48+
public static function SendImpressionForVariationShown(
3949
SettingsModel $settings,
40-
$campaignId,
41-
$variationId,
50+
$payload,
4251
ContextModel $context
4352
) {
4453
// Get base properties for the event
@@ -50,17 +59,75 @@ public static function createAndSendImpressionForVariationShown(
5059
$context->getIpAddress()
5160
);
5261

53-
// Construct payload data for tracking the user
54-
$payload = $networkUtil->getTrackUserPayloadData(
55-
$settings,
56-
EventEnum::VWO_VARIATION_SHOWN,
57-
$campaignId,
58-
$variationId,
59-
$context
60-
);
61-
6262
// Send the constructed properties and payload as a POST request
6363
$networkUtil->sendPostApiRequest($properties, $payload);
6464
}
65+
66+
/**
67+
* Sends a batch of events to the VWO server.
68+
*
69+
* @param array $batchPayload The batch payload to send.
70+
* @return bool True if the batch of events was sent successfully, false otherwise.
71+
*/
72+
public static function SendImpressionForVariationShownInBatch($batchPayload) {
73+
return self::sendBatchEvents($batchPayload);
74+
}
75+
76+
/**
77+
* Sends a batch of events to the VWO server.
78+
*
79+
* @param array $batchPayload The batch payload to send.
80+
* @return bool True if the batch of events was sent successfully, false otherwise.
81+
*/
82+
private static function sendBatchEvents($batchPayload) {
83+
$accountId = SettingsService::instance()->accountId ?? null;
84+
$retryConfig = NetworkManager::instance()->getRetryConfig();
85+
86+
$networkUtil = new NetworkUtil();
87+
$properties = $networkUtil->getEventBatchingQueryParams($accountId);
88+
$headers = [];
89+
$headers[HeadersEnum::AUTHORIZATION] = SettingsService::instance()->sdkKey;
90+
91+
$eventCount = is_array($batchPayload) ? count($batchPayload) : 1;
92+
$batchPayload = [
93+
'ev' => $batchPayload
94+
];
95+
96+
97+
$request = new RequestModel(
98+
UrlService::getBaseUrl(),
99+
'POST',
100+
UrlEnum::BATCH_EVENTS,
101+
$properties,
102+
$batchPayload,
103+
$headers,
104+
SettingsService::instance()->protocol,
105+
SettingsService::instance()->port,
106+
$retryConfig
107+
);
108+
109+
try {
110+
$response = NetworkManager::instance()->post($request);
111+
$statusCode = $response->getStatusCode();
112+
113+
// When shouldWaitForTrackingCalls is false, socket connections are used (fire-and-forget)
114+
// No status code is available, so we don't log success (we can't verify it)
115+
if ($statusCode === null) {
116+
LogManager::instance()->info('Impression sent to VWO server via socket connection for ' . $eventCount . ' events.');
117+
return true;
118+
}
119+
120+
if ($statusCode == 200) {
121+
LogManager::instance()->info('Impression sent successfully for ' . $eventCount . ' events.');
122+
return true;
123+
} else {
124+
LogManager::instance()->error('Impression failed to send for ' . $eventCount . ' events');
125+
return false;
126+
}
127+
} catch (\Exception $e) {
128+
LogManager::instance()->error('Error occurred while sending impressions. Error:' . $e->getMessage());
129+
return false;
130+
}
131+
}
65132
}
66133

src/Utils/NetworkUtil.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ public function getEventBatchingQueryParams($accountId)
121121
'a' => $accountId,
122122
'sd' => Constants::SDK_NAME,
123123
'sv' => $sdkVersion,
124+
'env' => SettingsService::instance()->sdkKey
124125
];
125126

126127
return $path;

src/Utils/RuleEvaluationUtil.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
use vwo\Utils\DataTypeUtil;
2626
use vwo\Utils\DecisionUtil;
2727
use vwo\Utils\ImpressionUtil;
28+
use vwo\Utils\NetworkUtil;
2829
use vwo\Models\User\ContextModel;
30+
use vwo\Enums\EventEnum;
2931

3032
class RuleEvaluationUtil
3133
{
@@ -57,6 +59,7 @@ public static function evaluateRule($settings, $feature, $campaign, $context, &$
5759
$storageService,
5860
$decision
5961
);
62+
$payload = null;
6063

6164
// If pre-segmentation is successful and a whitelisted object exists, proceed to send an impression
6265
if ($preSegmentationResult && DataTypeUtil::isObject($whitelistedObject) && count((array) $whitelistedObject) > 0) {
@@ -66,16 +69,16 @@ public static function evaluateRule($settings, $feature, $campaign, $context, &$
6669
'experimentKey' => $campaign->getKey(),
6770
'experimentVariationId' => $whitelistedObject['variationId'],
6871
]);
69-
7072
// Send an impression for the variation shown
7173
// if settings passed in init options is true, then we don't need to send an impression
7274
if (!$isDebuggerUsed) {
73-
ImpressionUtil::createAndSendImpressionForVariationShown($settings, $campaign->getId(), $whitelistedObject['variation']->getId(), $context);
75+
$networkUtil = new NetworkUtil();
76+
$payload = $networkUtil->getTrackUserPayloadData($settings, EventEnum::VWO_VARIATION_SHOWN, $campaign->getId(), $whitelistedObject['variation']->getId(), $context);
7477
}
7578
}
7679

7780
// Return the results of the evaluation
78-
return ['preSegmentationResult' => $preSegmentationResult, 'whitelistedObject' => $whitelistedObject, 'updatedDecision' => $decision];
81+
return ['preSegmentationResult' => $preSegmentationResult, 'whitelistedObject' => $whitelistedObject, 'updatedDecision' => $decision, 'payload' => $payload];
7982
}
8083
}
8184
?>

0 commit comments

Comments
 (0)