Skip to content

Commit 0165dee

Browse files
committed
[FSSDK-11459] Ruby - Add SDK Multi-Region Support for Data Hosting
1 parent 95f9e35 commit 0165dee

10 files changed

+111
-60
lines changed

lib/optimizely/config/datafile_project_config.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class DatafileProjectConfig < ProjectConfig
3232
:group_id_map, :rollout_id_map, :rollout_experiment_id_map, :variation_id_map,
3333
:variation_id_to_variable_usage_map, :variation_key_map, :variation_id_map_by_experiment_id,
3434
:variation_key_map_by_experiment_id, :flag_variation_map, :integration_key_map, :integrations,
35-
:public_key_for_odp, :host_for_odp, :all_segments
35+
:public_key_for_odp, :host_for_odp, :all_segments, :region
3636
# Boolean - denotes if Optimizely should remove the last block of visitors' IP address before storing event data
3737
attr_reader :anonymize_ip
3838

@@ -68,6 +68,7 @@ def initialize(datafile, logger, error_handler)
6868
@rollouts = config.fetch('rollouts', [])
6969
@send_flag_decisions = config.fetch('sendFlagDecisions', false)
7070
@integrations = config.fetch('integrations', [])
71+
@region = config.fetch('region', 'US')
7172

7273
# Json type is represented in datafile as a subtype of string for the sake of backwards compatibility.
7374
# Converting it to a first-class json type while creating Project Config

lib/optimizely/event/event_factory.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ class EventFactory
2828
# EventFactory builds LogEvent objects from a given user_event.
2929
class << self
3030
CUSTOM_ATTRIBUTE_FEATURE_TYPE = 'custom'
31-
ENDPOINT = 'https://logx.optimizely.com/v1/events'
31+
ENDPOINTS = {
32+
US: 'https://logx.optimizely.com/v1/events',
33+
EU: 'https://eu.logx.optimizely.com/v1/events'
34+
}
3235
POST_HEADERS = {'Content-Type' => 'application/json'}.freeze
3336
ACTIVATE_EVENT_KEY = 'campaign_activated'
3437

@@ -64,9 +67,13 @@ def create_log_event(user_events, logger)
6467
builder.with_client_name(user_context[:client_name])
6568
builder.with_anonymize_ip(user_context[:anonymize_ip])
6669
builder.with_enrich_decisions(true)
70+
builder.with_region(user_context[:region])
6771

6872
builder.with_visitors(visitors)
6973
event_batch = builder.build
74+
75+
ENDPOINT = ENDPOINTS[user_context[:region].to_sym] || ENDPOINTS[:US]
76+
7077
Event.new(:post, ENDPOINT, event_batch.as_json, POST_HEADERS)
7178
end
7279

lib/optimizely/event/user_event_factory.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def self.create_impression_event(project_config, experiment, variation_id, metad
3333
#
3434
# Returns Event encapsulating the impression event.
3535
event_context = Optimizely::EventContext.new(
36+
region: project_config.region,
3637
account_id: project_config.account_id,
3738
project_id: project_config.project_id,
3839
anonymize_ip: project_config.anonymize_ip,
@@ -67,6 +68,7 @@ def self.create_conversion_event(project_config, event, user_id, user_attributes
6768
# Returns Event encapsulating the conversion event.
6869

6970
event_context = Optimizely::EventContext.new(
71+
region: project_config.region,
7072
account_id: project_config.account_id,
7173
project_id: project_config.project_id,
7274
anonymize_ip: project_config.anonymize_ip,

lib/optimizely/event_builder.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ def get_common_params(project_config, user_id, attributes)
107107
end
108108

109109
class EventBuilder < BaseEventBuilder
110-
ENDPOINT = 'https://logx.optimizely.com/v1/events'
110+
ENDPOINTS = {
111+
US: 'https://logx.optimizely.com/v1/events',
112+
EU: 'https://eu.logx.optimizely.com/v1/events'
113+
}
111114
POST_HEADERS = {'Content-Type' => 'application/json'}.freeze
112115
ACTIVATE_EVENT_KEY = 'campaign_activated'
113116

@@ -122,10 +125,13 @@ def create_impression_event(project_config, experiment, variation_id, user_id, a
122125
#
123126
# Returns +Event+ encapsulating the impression event.
124127

128+
region = project_config.region || 'US'
125129
event_params = get_common_params(project_config, user_id, attributes)
126130
impression_params = get_impression_params(project_config, experiment, variation_id)
127131
event_params[:visitors][0][:snapshots].push(impression_params)
128132

133+
ENDPOINT = ENDPOINTS[region]
134+
129135
Event.new(:post, ENDPOINT, event_params, POST_HEADERS)
130136
end
131137

@@ -140,10 +146,13 @@ def create_conversion_event(project_config, event, user_id, attributes, event_ta
140146
#
141147
# Returns +Event+ encapsulating the conversion event.
142148

149+
region = project_config.region || 'US'
143150
event_params = get_common_params(project_config, user_id, attributes)
144151
conversion_params = get_conversion_params(event, event_tags)
145152
event_params[:visitors][0][:snapshots] = [conversion_params]
146153

154+
ENDPOINT = ENDPOINTS[region]
155+
147156
Event.new(:post, ENDPOINT, event_params, POST_HEADERS)
148157
end
149158

lib/optimizely/project_config.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ def host_for_odp; end
6262

6363
def all_segments; end
6464

65+
def region; end
66+
6567
def experiment_running?(experiment); end
6668

6769
def get_experiment_from_key(experiment_key); end

spec/config/datafile_project_config_spec.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
expect(project_config.sdk_key).to eq(config_body['sdkKey'])
5858
expect(project_config.environment_key).to eq(config_body['environmentKey'])
5959
expect(project_config.send_flag_decisions).to eq(config_body['sendFlagDecisions'])
60+
expect(project_config.region).to eq(config_body['region'])
6061

6162
expected_attribute_key_map = {
6263
'browser_type' => config_body['attributes'][0],
@@ -756,6 +757,23 @@
756757
expect(project_config.rollout_experiment_id_map).to eq(expected_rollout_experiment_id_map)
757758
end
758759

760+
it 'should use US region when no region is specified in datafile' do
761+
project_config = Optimizely::DatafileProjectConfig.new(config_body_JSON, logger, error_handler)
762+
expect(project_config.region).to eq('US')
763+
end
764+
765+
it 'should parse region specified in datafile correctly' do
766+
project_configUS = Optimizely::DatafileProjectConfig.new(config_body_JSON, logger, error_handler)
767+
expect(project_config.region).to eq('US')
768+
769+
config_bodyEU = config_body.dup
770+
config_bodyEU['region'] = 'EU'
771+
config_body_JSON = JSON.dump(config_bodyEU)
772+
project_configEU = Optimizely::DatafileProjectConfig.new(config_body_JSON, logger, error_handler)
773+
774+
expect(project_config.region).to eq('EU')
775+
end
776+
759777
it 'should initialize properties correctly upon creating project with typed audience dict' do
760778
project_config = Optimizely::DatafileProjectConfig.new(JSON.dump(OptimizelySpec::CONFIG_DICT_WITH_TYPED_AUDIENCES), logger, error_handler)
761779
config_body = OptimizelySpec::CONFIG_DICT_WITH_TYPED_AUDIENCES

spec/event/event_factory_spec.rb

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@
3434
allow(Time).to receive(:now).and_return(time_now)
3535
allow(SecureRandom).to receive(:uuid).and_return('a68cf1ad-0393-4e18-af87-efe8f01a7c9c')
3636

37-
@expected_endpoint = 'https://logx.optimizely.com/v1/events'
37+
@expected_endpoints[:US] = {
38+
US: 'https://logx.optimizely.com/v1/events',
39+
EU: 'https://eu.logx.optimizely.com/v1/events'
40+
}
3841
@expected_impression_params = {
3942
account_id: '12001',
4043
project_id: '111001',
@@ -111,7 +114,7 @@
111114
impression_event = Optimizely::UserEventFactory.create_impression_event(project_config, experiment, '111128', metadata, 'test_user', nil)
112115
log_event = Optimizely::EventFactory.create_log_event(impression_event, spy_logger)
113116
expect(log_event.params).to eq(@expected_impression_params)
114-
expect(log_event.url).to eq(@expected_endpoint)
117+
expect(log_event.url).to eq(@expected_endpoints[:US])
115118
expect(log_event.http_verb).to eq(:post)
116119
end
117120

@@ -134,7 +137,7 @@
134137
'browser_type' => 'firefox')
135138
log_event = Optimizely::EventFactory.create_log_event(impression_event, spy_logger)
136139
expect(log_event.params).to eq(@expected_impression_params)
137-
expect(log_event.url).to eq(@expected_endpoint)
140+
expect(log_event.url).to eq(@expected_endpoints[:US])
138141
expect(log_event.http_verb).to eq(:post)
139142
end
140143

@@ -184,7 +187,7 @@
184187
impression_event = Optimizely::UserEventFactory.create_impression_event(project_config, experiment, '111128', metadata, 'test_user', attributes)
185188
log_event = Optimizely::EventFactory.create_log_event(impression_event, spy_logger)
186189
expect(log_event.params).to eq(@expected_impression_params)
187-
expect(log_event.url).to eq(@expected_endpoint)
190+
expect(log_event.url).to eq(@expected_endpoints[:US])
188191
expect(log_event.http_verb).to eq(:post)
189192
end
190193

@@ -225,7 +228,7 @@
225228
impression_event = Optimizely::UserEventFactory.create_impression_event(project_config, experiment, '111128', metadata, 'test_user', attributes)
226229
log_event = Optimizely::EventFactory.create_log_event(impression_event, spy_logger)
227230
expect(log_event.params).to eq(@expected_impression_params)
228-
expect(log_event.url).to eq(@expected_endpoint)
231+
expect(log_event.url).to eq(@expected_endpoints[:US])
229232
expect(log_event.http_verb).to eq(:post)
230233
end
231234

@@ -248,7 +251,7 @@
248251
'browser_type' => false)
249252
log_event = Optimizely::EventFactory.create_log_event(impression_event, spy_logger)
250253
expect(log_event.params).to eq(@expected_impression_params)
251-
expect(log_event.url).to eq(@expected_endpoint)
254+
expect(log_event.url).to eq(@expected_endpoints[:US])
252255
expect(log_event.http_verb).to eq(:post)
253256
end
254257

@@ -270,7 +273,7 @@
270273
impression_event = Optimizely::UserEventFactory.create_impression_event(project_config, experiment, '111128', metadata, 'test_user', 'browser_type' => 0)
271274
log_event = Optimizely::EventFactory.create_log_event(impression_event, spy_logger)
272275
expect(log_event.params).to eq(@expected_impression_params)
273-
expect(log_event.url).to eq(@expected_endpoint)
276+
expect(log_event.url).to eq(@expected_endpoints[:US])
274277
expect(log_event.http_verb).to eq(:post)
275278
end
276279

@@ -286,15 +289,15 @@
286289
invalid_attribute: 'sorry_not_sorry')
287290
log_event = Optimizely::EventFactory.create_log_event(impression_event, spy_logger)
288291
expect(log_event.params).to eq(@expected_impression_params)
289-
expect(log_event.url).to eq(@expected_endpoint)
292+
expect(log_event.url).to eq(@expected_endpoints[:US])
290293
expect(log_event.http_verb).to eq(:post)
291294
end
292295

293296
it 'should create a valid Event when create_conversion_event is called' do
294297
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, nil)
295298
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
296299
expect(log_event.params).to eq(@expected_conversion_params)
297-
expect(log_event.url).to eq(@expected_endpoint)
300+
expect(log_event.url).to eq(@expected_endpoints[:US])
298301
expect(log_event.http_verb).to eq(:post)
299302
end
300303

@@ -309,7 +312,7 @@
309312
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', {'browser_type' => 'firefox'}, nil)
310313
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
311314
expect(log_event.params).to eq(@expected_conversion_params)
312-
expect(log_event.url).to eq(@expected_endpoint)
315+
expect(log_event.url).to eq(@expected_endpoints[:US])
313316
expect(log_event.http_verb).to eq(:post)
314317
end
315318

@@ -322,7 +325,7 @@
322325
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, event_tags)
323326
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
324327
expect(log_event.params).to eq(@expected_conversion_params)
325-
expect(log_event.url).to eq(@expected_endpoint)
328+
expect(log_event.url).to eq(@expected_endpoints[:US])
326329
expect(log_event.http_verb).to eq(:post)
327330
end
328331

@@ -335,7 +338,7 @@
335338
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, event_tags)
336339
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
337340
expect(log_event.params).to eq(@expected_conversion_params)
338-
expect(log_event.url).to eq(@expected_endpoint)
341+
expect(log_event.url).to eq(@expected_endpoints[:US])
339342
expect(log_event.http_verb).to eq(:post)
340343
end
341344

@@ -347,7 +350,7 @@
347350
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, event_tags)
348351
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
349352
expect(log_event.params).to eq(@expected_conversion_params)
350-
expect(log_event.url).to eq(@expected_endpoint)
353+
expect(log_event.url).to eq(@expected_endpoints[:US])
351354
expect(log_event.http_verb).to eq(:post)
352355
end
353356

@@ -359,7 +362,7 @@
359362
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, event_tags)
360363
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
361364
expect(log_event.params).to eq(@expected_conversion_params)
362-
expect(log_event.url).to eq(@expected_endpoint)
365+
expect(log_event.url).to eq(@expected_endpoints[:US])
363366
expect(log_event.http_verb).to eq(:post)
364367
end
365368

@@ -375,7 +378,7 @@
375378
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, event_tags)
376379
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
377380
expect(log_event.params).to eq(@expected_conversion_params)
378-
expect(log_event.url).to eq(@expected_endpoint)
381+
expect(log_event.url).to eq(@expected_endpoints[:US])
379382
expect(log_event.http_verb).to eq(:post)
380383
end
381384

@@ -390,7 +393,7 @@
390393
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, event_tags)
391394
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
392395
expect(log_event.params).to eq(@expected_conversion_params)
393-
expect(log_event.url).to eq(@expected_endpoint)
396+
expect(log_event.url).to eq(@expected_endpoints[:US])
394397
expect(log_event.http_verb).to eq(:post)
395398
end
396399

@@ -404,7 +407,7 @@
404407
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, event_tags)
405408
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
406409
expect(log_event.params).to eq(@expected_conversion_params)
407-
expect(log_event.url).to eq(@expected_endpoint)
410+
expect(log_event.url).to eq(@expected_endpoints[:US])
408411
expect(log_event.http_verb).to eq(:post)
409412
end
410413

@@ -418,7 +421,7 @@
418421
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, event_tags)
419422
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
420423
expect(log_event.params).to eq(@expected_conversion_params)
421-
expect(log_event.url).to eq(@expected_endpoint)
424+
expect(log_event.url).to eq(@expected_endpoints[:US])
422425
expect(log_event.http_verb).to eq(:post)
423426
end
424427

@@ -432,7 +435,7 @@
432435
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, event_tags)
433436
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
434437
expect(log_event.params).to eq(@expected_conversion_params)
435-
expect(log_event.url).to eq(@expected_endpoint)
438+
expect(log_event.url).to eq(@expected_endpoints[:US])
436439
expect(log_event.http_verb).to eq(:post)
437440
end
438441

@@ -447,7 +450,7 @@
447450
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, event_tags)
448451
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
449452
expect(log_event.params).to eq(@expected_conversion_params)
450-
expect(log_event.url).to eq(@expected_endpoint)
453+
expect(log_event.url).to eq(@expected_endpoints[:US])
451454
expect(log_event.http_verb).to eq(:post)
452455
end
453456

@@ -461,7 +464,7 @@
461464
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', nil, event_tags)
462465
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
463466
expect(log_event.params).to eq(@expected_conversion_params)
464-
expect(log_event.url).to eq(@expected_endpoint)
467+
expect(log_event.url).to eq(@expected_endpoints[:US])
465468
expect(log_event.http_verb).to eq(:post)
466469
end
467470

@@ -487,7 +490,7 @@
487490
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', {'browser_type' => 'firefox'}, event_tags)
488491
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
489492
expect(log_event.params).to eq(@expected_conversion_params)
490-
expect(log_event.url).to eq(@expected_endpoint)
493+
expect(log_event.url).to eq(@expected_endpoints[:US])
491494
expect(log_event.http_verb).to eq(:post)
492495
end
493496

@@ -520,7 +523,7 @@
520523
impression_event = Optimizely::UserEventFactory.create_impression_event(project_config, experiment, '111128', metadata, 'test_user', user_attributes)
521524
log_event = Optimizely::EventFactory.create_log_event(impression_event, spy_logger)
522525
expect(log_event.params).to eq(@expected_impression_params)
523-
expect(log_event.url).to eq(@expected_endpoint)
526+
expect(log_event.url).to eq(@expected_endpoints[:US])
524527
expect(log_event.http_verb).to eq(:post)
525528
end
526529

@@ -556,7 +559,7 @@
556559
impression_event = Optimizely::UserEventFactory.create_impression_event(project_config, experiment, '111128', metadata, 'test_user', user_attributes)
557560
log_event = Optimizely::EventFactory.create_log_event(impression_event, spy_logger)
558561
expect(log_event.params).to eq(@expected_impression_params)
559-
expect(log_event.url).to eq(@expected_endpoint)
562+
expect(log_event.url).to eq(@expected_endpoints[:US])
560563
expect(log_event.http_verb).to eq(:post)
561564
end
562565

@@ -594,7 +597,7 @@
594597
)
595598
log_event = Optimizely::EventFactory.create_log_event(impression_event, spy_logger)
596599
expect(log_event.params).to eq(@expected_impression_params)
597-
expect(log_event.url).to eq(@expected_endpoint)
600+
expect(log_event.url).to eq(@expected_endpoints[:US])
598601
expect(log_event.http_verb).to eq(:post)
599602
end
600603

@@ -620,7 +623,7 @@
620623
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', user_attributes, nil)
621624
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
622625
expect(log_event.params).to eq(@expected_conversion_params)
623-
expect(log_event.url).to eq(@expected_endpoint)
626+
expect(log_event.url).to eq(@expected_endpoints[:US])
624627
expect(log_event.http_verb).to eq(:post)
625628
end
626629

@@ -642,7 +645,7 @@
642645
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', user_attributes, nil)
643646
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
644647
expect(log_event.params).to eq(@expected_conversion_params)
645-
expect(log_event.url).to eq(@expected_endpoint)
648+
expect(log_event.url).to eq(@expected_endpoints[:US])
646649
expect(log_event.http_verb).to eq(:post)
647650
end
648651

@@ -671,7 +674,7 @@
671674
conversion_event = Optimizely::UserEventFactory.create_conversion_event(project_config, event, 'test_user', user_attributes, nil)
672675
log_event = Optimizely::EventFactory.create_log_event(conversion_event, spy_logger)
673676
expect(log_event.params).to eq(@expected_conversion_params)
674-
expect(log_event.url).to eq(@expected_endpoint)
677+
expect(log_event.url).to eq(@expected_endpoints[:US])
675678
expect(log_event.http_verb).to eq(:post)
676679
end
677680
end

0 commit comments

Comments
 (0)