[FSSDK-11458] Python - Add SDK Multi-Region Support for Data Hosting#459
[FSSDK-11458] Python - Add SDK Multi-Region Support for Data Hosting#459esrakartalOpt merged 36 commits intomasterfrom
Conversation
…o esra/FSSDK-11458_eu_hosting
| ) | ||
|
|
||
| self.assertEqual(self.project_config.region, impression_event.event_context.region) | ||
| self.assertEqual('EU', impression_event.event_context.region) |
There was a problem hiding this comment.
can we also add a test for create_contervsion_event?
tests/test_event_processor.py
Outdated
|
|
||
| def dispatch_event(self, log_event): | ||
| if log_event.http_verb == 'POST' and log_event.url == EventFactory.EVENT_ENDPOINT: | ||
| if log_event.url in EventFactory.EVENT_ENDPOINTS.values(): |
There was a problem hiding this comment.
the log_event.http_verb == 'POST' condition got removed. Can we keep that check?
| expected_params, | ||
| EventFactory.HTTP_VERB, | ||
| EventFactory.HTTP_HEADERS, | ||
| ) |
There was a problem hiding this comment.
can we add a test to check that create_log_event works correctly with EU region?
There was a problem hiding this comment.
Pull Request Overview
This PR adds multi-region support for data hosting in the Optimizely Python SDK, allowing events to be sent to region-specific endpoints (US or EU) based on project configuration.
- Added Region enum with US and EU values to project configuration
- Updated event factories and builders to use region-specific endpoints
- Enhanced event context to include region information
Reviewed Changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| optimizely/project_config.py | Added Region enum and region configuration parsing with US as default |
| optimizely/event/user_event.py | Updated EventContext to accept and store region parameter |
| optimizely/event/user_event_factory.py | Modified factory methods to pass region to EventContext |
| optimizely/event/event_factory.py | Replaced single endpoint with region-specific endpoint mapping |
| optimizely/event_builder.py | Updated to use region-specific URLs for event creation |
| tests/test_config.py | Added tests for region configuration parsing |
| tests/test_user_event_factory.py | Added tests for region handling in event creation |
| tests/test_event_factory.py | Updated tests to use new endpoint structure |
| tests/test_event_builder.py | Updated tests for region-specific event building |
| tests/test_event_processor.py | Updated test to handle multiple endpoints |
| self.client_name = CLIENT_NAME | ||
| self.client_version = version.__version__ | ||
| self.anonymize_ip = anonymize_ip | ||
| self.region = region or 'US' |
There was a problem hiding this comment.
The fallback logic uses a string literal 'US' instead of the Region enum. Consider using self.region = region or Region.US for consistency with the type system.
| self.region = region or 'US' | |
| self.region = region or Region.US |
There was a problem hiding this comment.
I second htis use. If yuo have Region class somewhere, then we should call country attribute on the Region object.
optimizely/event_builder.py
Outdated
| region = project_config.region.value if hasattr(project_config.region, 'value') else 'US' | ||
| events_url = self.EVENTS_URLS.get(str(region), self.EVENTS_URLS['US']) |
There was a problem hiding this comment.
The fallback to string literal 'US' should use Region.US.value for consistency. Also, this hasattr check suggests uncertainty about the type - consider using isinstance(project_config.region, Region) for more explicit type checking.
| region = project_config.region.value if hasattr(project_config.region, 'value') else 'US' | |
| events_url = self.EVENTS_URLS.get(str(region), self.EVENTS_URLS['US']) | |
| region = project_config.region.value if isinstance(project_config.region, Region) else Region.US.value | |
| events_url = self.EVENTS_URLS.get(str(region), self.EVENTS_URLS[Region.US.value]) |
There was a problem hiding this comment.
Again, I agree with copilot lol
optimizely/event_builder.py
Outdated
| region = project_config.region.value if hasattr(project_config.region, 'value') else 'US' | ||
| events_url = self.EVENTS_URLS.get(str(region), self.EVENTS_URLS['US']) |
There was a problem hiding this comment.
Same issue as line 272 - the fallback to string literal 'US' should use Region.US.value for consistency, and the hasattr check could be replaced with more explicit type checking.
| region = project_config.region.value if hasattr(project_config.region, 'value') else 'US' | |
| events_url = self.EVENTS_URLS.get(str(region), self.EVENTS_URLS['US']) | |
| region = project_config.region.value if isinstance(project_config.region, enums.Region) else enums.Region.US.value | |
| events_url = self.EVENTS_URLS.get(str(region), self.EVENTS_URLS[enums.Region.US.value]) |
| '111129', | ||
| 'test_user', | ||
| {'do_you_know_me': 'test_value'}, | ||
| {'do_you_know_me': 'test_value'} |
There was a problem hiding this comment.
[nitpick] Removed trailing comma in function call. While this change works, trailing commas in multi-line function calls are often preferred for easier version control diffs.
| {'do_you_know_me': 'test_value'} | |
| {'do_you_know_me': 'test_value',} |
| '111129', | ||
| 'test_user', | ||
| attributes, | ||
| attributes |
There was a problem hiding this comment.
[nitpick] Removed trailing comma in function call. While this change works, trailing commas in multi-line function calls are often preferred for easier version control diffs.
| attributes | |
| attributes, |
| '111129', | ||
| 'test_user', | ||
| {'$opt_user_agent': 'Edge'}, | ||
| {'$opt_user_agent': 'Edge'} |
There was a problem hiding this comment.
[nitpick] Removed trailing comma in function call. While this change works, trailing commas in multi-line function calls are often preferred for easier version control diffs.
| {'$opt_user_agent': 'Edge'} | |
| {'$opt_user_agent': 'Edge',} |
pvcraven
left a comment
There was a problem hiding this comment.
If we specify a region that doesn't exist, what happens? Does 'ZZ' fall back to 'US'? I think this is what happens. I'd like to see tests verifying what happens in this case. (Do we need to log something if we are passed an invalid region?)
jaeopt
left a comment
There was a problem hiding this comment.
Looks good! We can consider string-type region for simple.
optimizely/event/event_factory.py
Outdated
| region = user_context.region | ||
| if hasattr(region, 'value'): | ||
| region_str = region.value | ||
| elif region is None: | ||
| region_str = 'US' # Default to US | ||
| else: | ||
| region_str = str(region) |
There was a problem hiding this comment.
We can consider using a simple string type for region. The region will be handled in type-safe way when building into datafile. It looks like fallback to "US" for safety is good enough?
There was a problem hiding this comment.
@jaeopt by string type do you mean using Region.US instead of string 'US'?
That's what I have been suggesting further down the code. Just we don't contradict each other.
There was a problem hiding this comment.
I mean we get string-type of region from datafile, and we can pass it down all the way to EventDispatcher to determine the URL (with fallback to US). The source of this region is datafile. Not much value of this enum-based type checking. It may be risky if you use defined enum set for strong-typed SDKs when we add new countries in the server.
optimizely/project_config.py
Outdated
| region_value = config.get('region') | ||
| self.region: Region | ||
| if region_value == Region.EU.value: | ||
| self.region = Region.EU | ||
| else: | ||
| self.region = Region.US |
There was a problem hiding this comment.
Another area we can get benefits with string type. No need to change the code when we add countries.
| self.client_name = CLIENT_NAME | ||
| self.client_version = version.__version__ | ||
| self.anonymize_ip = anonymize_ip | ||
| self.region = region or 'US' |
There was a problem hiding this comment.
I second htis use. If yuo have Region class somewhere, then we should call country attribute on the Region object.
optimizely/event_builder.py
Outdated
| region = project_config.region.value if hasattr(project_config.region, 'value') else 'US' | ||
| events_url = self.EVENTS_URLS.get(str(region), self.EVENTS_URLS['US']) |
There was a problem hiding this comment.
Again, I agree with copilot lol
optimizely/event/event_factory.py
Outdated
| region = user_context.region | ||
| if hasattr(region, 'value'): | ||
| region_str = region.value | ||
| elif region is None: | ||
| region_str = 'US' # Default to US | ||
| else: | ||
| region_str = str(region) |
There was a problem hiding this comment.
@jaeopt by string type do you mean using Region.US instead of string 'US'?
That's what I have been suggesting further down the code. Just we don't contradict each other.
@pvcraven Locally, I have created a test case as below for invalid region. It returned US endpoint. |
Summary
Test plan
Issues