Skip to content

Commit e2819fa

Browse files
fix: add timezone for BackgroundScheduler, rename eval function to value (#4)
* fix: add timezone for BackgroundScheduler, rename eval function to value * chore: add license header(s) * style: format python code (pep8) * fix tz * style: format python code (pep8) Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 938ac6d commit e2819fa

8 files changed

Lines changed: 39 additions & 34 deletions

File tree

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ jobs:
3737
run: pytest --cov featureprobe
3838

3939
- name: Upload coverage to Codecov
40+
if: ${{ matrix.python }} == '3.8'
4041
uses: codecov/codecov-action@v3

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ First, install the FeatureProbe SDK as a dependency in your application.
4949
pip3 install featureprobe-server
5050
```
5151

52+
> You may get the latest version of this repo (not released) via [TestPyPI](https://test.pypi.org/project/featureprobe-server/)
53+
5254
<!-- WIP
5355
#### conda
5456
@@ -87,11 +89,11 @@ if __name__ == '__main__':
8789
'userId': '9876',
8890
'tel': '12345678998',
8991
})
90-
bool_eval = bool(client.evaluate('bool_toggle_key', user, default=False))
92+
bool_eval = bool(client.value('bool_toggle_key', user, default=False))
9193
if bool_eval:
92-
# application code to show the feature
94+
... # application code to show the feature
9395
else:
94-
# the code to run if the feature is off
96+
... # the code to run if the feature is off
9597
```
9698

9799

demo.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,28 @@
55
logging.basicConfig(level=logging.WARNING)
66

77
if __name__ == '__main__':
8-
config = fp.Config(remote_uri='http://127.0.0.1:4007', # FeatureProbe server URL
8+
# FEATURE_PROBE_SERVER_URL = 'http://localhost:4007' # for local docker
9+
FEATURE_PROBE_SERVER_URL = 'https://featureprobe.io/server' # for featureprobe.io
10+
11+
config = fp.Config(remote_uri=FEATURE_PROBE_SERVER_URL, # FeatureProbe server URL
912
sync_mode='pooling',
1013
refresh_interval=3)
1114

12-
client = fp.Client('server-8ed48815ef044428826787e9a238b9c6a479f98c',
15+
client = fp.Client('server-b8b7c58417680d9e76b1b8454326f357296b5003',
1316
# Server Side SDK Key for your project and environment
1417
config)
1518

16-
# create one user, with id='user_unique_id' and one attribute
17-
user = fp.User('user_unique_id', {'city': 'New York'})
18-
discount = float(client.evaluate('promotion_activity', # Toggle you want to use
19-
user, default=0))
20-
print('user in New York has a discount of : %d' % discount)
21-
22-
detail = client.evaluate_detail('promotion_activity', user, default=0)
23-
print('detail: %s' % detail.reason)
24-
# rule_index = None on default rule is hit
25-
print('rule index: ' + str(detail.rule_index))
19+
# create one user
20+
# key is for percentage rollout, normally use userId as key
21+
user = fp.User('00001', {'userId': '00001'})
2622

27-
user2 = fp.User('user_id2')
28-
# create another user, here's the alternative way to set user attributes
29-
user2['city'] = 'Paris'
23+
# Toggle you want to use
24+
TOGGLE_KEY = 'feature_toggle02'
3025

31-
discount = float(client.evaluate('promotion_activity', user2, default=0))
32-
print('user in Paris has a discount of : %d' % discount)
26+
# get toggle result for this user
27+
is_open = client.value(TOGGLE_KEY, user, default=False)
28+
print('feature for this user is: ' + str(is_open))
3329

34-
detail2 = client.evaluate_detail('promotion_activity', user2, default=0)
35-
print('detail2: %s' % detail2.reason)
36-
print('rule index: %d' % detail2.rule_index)
30+
is_open_detail = client.value_detail(TOGGLE_KEY, user, default=False)
31+
print('detail: ' + str(is_open_detail.reason))
32+
print('rule index: ' + str(is_open_detail.rule_index))

featureprobe/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def __init__(self, sdk_key: str, config: Config = Config()):
3535
def flush(self):
3636
self._event_processor.flush()
3737

38-
def evaluate(self, toggle_key: str, user: User, default) -> Any:
38+
def value(self, toggle_key: str, user: User, default) -> Any:
3939
toggle = self._data_repo.get_toggle(toggle_key)
4040
segments = self._data_repo.get_all_segment()
4141
if not toggle:
@@ -51,7 +51,7 @@ def evaluate(self, toggle_key: str, user: User, default) -> Any:
5151
self._event_processor.push(access_event)
5252
return eval_result.value
5353

54-
def evaluate_detail(self, toggle_key: str, user: User, default) -> Detail:
54+
def value_detail(self, toggle_key: str, user: User, default) -> Detail:
5555
if not self._data_repo.initialized:
5656
return Detail(
5757
value=default,

featureprobe/default_event_processor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
# limitations under the License.
1414

1515
import contextlib
16-
import json
1716
import logging
1817
import queue
1918
import threading
@@ -23,6 +22,7 @@
2322
from queue import Queue
2423
from typing import List, Optional
2524

25+
import tzlocal
2626
from apscheduler.schedulers.background import BackgroundScheduler
2727
from requests import Session, HTTPError
2828

@@ -109,7 +109,7 @@ def __init__(self, context: Context):
109109
handler_thread.start()
110110

111111
self._executor = ThreadPoolExecutor(max_workers=5)
112-
self._scheduler = BackgroundScheduler()
112+
self._scheduler = BackgroundScheduler(timezone=tzlocal.get_localzone())
113113
self._scheduler.start()
114114
self._scheduler.add_job(self.flush,
115115
trigger='interval',

featureprobe/pooling_synchronizer.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from datetime import datetime
1818
from typing import TYPE_CHECKING
1919

20+
import tzlocal
2021
from apscheduler.schedulers.background import BackgroundScheduler
2122
from requests import Session
2223

@@ -63,7 +64,8 @@ def sync(self):
6364
% self._refresh_interval.total_seconds() * 1000)
6465
self._poll()
6566
with self._lock:
66-
self._scheduler = BackgroundScheduler()
67+
self._scheduler = BackgroundScheduler(
68+
timezone=tzlocal.get_localzone())
6769
self._scheduler.start()
6870
self._scheduler.add_job(
6971
self._poll,

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
APScheduler~=3.0
2-
requests>=2.12.0
2+
requests>=2.12.0
3+
tzlocal~=2.0.0

tests/featureprobe_test.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import json
1616
import logging
17+
import re
1718

1819
import pytest
1920

@@ -79,14 +80,16 @@ def test_case():
7980
expect_value = expect_result['value']
8081

8182
if func_name.endswith('value'):
82-
assert server.evaluate(
83+
assert server.value(
8384
toggle_key, user, default_value) == expect_value
8485
elif func_name.endswith('detail'):
85-
detail = server.evaluate_detail(
86+
detail = server.value_detail(
8687
toggle_key, user, default_value)
8788
assert detail.value == expect_value
88-
# assert detail.reason == expect_result['reason']
89-
# assert detail.version == expect_result['version']
90-
# assert (detail.rule_index is None) == expect_result['no_rule_index']
89+
if expect_result.get('reason') is not None:
90+
assert re.search(
91+
expect_result.get('reason'),
92+
detail.reason,
93+
re.IGNORECASE)
9194
else:
9295
pytest.fail('should have no other cases yet')

0 commit comments

Comments
 (0)