Untitled
unknown
plain_text
2 years ago
7.2 kB
8
Indexable
CLUSTER_HOST = 'remote_host'
r = StrictRedis(CLUSTER_HOST, 6379)
"""
CREATE TABLE `experiments` (
`experiment_id` int AUTO_INCREMENT,
`title` varchar(100) NOT NULL,
`is_disabled` tinyint DEFAULT '0',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`start_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`end_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`experiment_id`)
) ENGINE = InnoDB
CREATE TABLE `experiment_variants` (
`variant_id` int AUTO_INCREMENT NOT NULL,
`experiment_id` int NOT NULL,
`title` varchar(50) NOT NULL,
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`variant_id`),
KEY `experiment_id` (`experiment_id`),
CONSTRAINT `experiment_variants_ibfk_1` FOREIGN KEY (`experiment_id`)
REFERENCES `experiments` (`experiment_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB
CREATE TABLE `device_experiments` (
`id` int AUTO_INCREMENT NOT NULL ,
`device_id` int NOT NULL,
`experiment_id` int NOT NULL,
`variant_id` int NOT NULL,
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `variant_id` (`variant_id`),
KEY `experiment_id` (`experiment_id`),
CONSTRAINT `device_experiments_ibfk_1` FOREIGN KEY (`variant_id`) REFERENCES `experiment_variants` (`variant_id`)
ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `device_experiments_ibfk_2` FOREIGN KEY (`experiment_id`) REFERENCES `experiments` (`experiment_id`)
ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB
"""
def get_experiment_by_id(experiment_id):
key, ttl = f"exp:detail:{experiment_id}", 3600 * 12
details = r.get(key)
if details:
return json.loads(details)
query = f"""SELECT * FROM experiments where experiment_id = '{experiment_id}'"""
cursor = connection.cursor()
cursor.execute(query)
data = cursor.fetchone()
cursor.close()
details = {}
if data:
details = data[0]
r.set(key, json.dumps(details))
r.expire(key, ttl)
return details
def get_variant_by_id(variant_id):
"""
Get variant details by variant id
:param variant_id: Variant Id
:type variant_id: str
:return: Variant Details
:rtype: dict
"""
cache_key, ttl = f'variant:detail:{variant_id}', 3600 * 12
variant = r.get(cache_key)
if variant:
variant_json = json.loads(variant)
return variant_json
query = f"""SELECT * FROM experiment_variants where variant_id = '{variant_id}'"""
cursor = connection.cursor()
cursor.execute(query)
data = cursor.fetchone()
cursor.close()
details = {}
if data:
details = data[0]
r.set(cache_key, json.dumps(details))
r.expire(cache_key, ttl)
return details
def get_variants_by_experiment_id(experiment_id):
cache_key, ttl = f'exp:variants:{experiment_id}', 3600 * 12
variant_details = r.get(cache_key)
if variant_details:
variants_list = json.loads(variant_details)
return variants_list
query = f"""SELECT variant_id FROM experiment_variants where experiment_id = '{experiment_id}'"""
cursor = connection.cursor()
cursor.execute(query)
data = cursor.fetchall()
cursor.close()
variant_ids = []
for row in data:
variant_id = row[0]
variant_ids.append(variant_id)
if variant_ids:
r.set(cache_key, json.dumps(variant_ids))
return variant_ids
def get_device_variant(device_id, experiment_id):
cache_key, ttl = f'device:experiment_var:{device_id}:{experiment_id}', 3600 * 12
variant = r.get(cache_key)
if variant:
variant_id = json.loads(variant)
return variant_id
query = f"""
SELECT variant_id FROM device_experiments
where device_id = '{device_id}' and experiment_id = '{experiment_id}'
"""
cursor = connection.cursor()
cursor.execute(query)
data = cursor.fetchone()
cursor.close()
variant_id = None
if data:
variant_id = data[0]
r.set(cache_key, json.dumps(variant_id))
r.expire(cache_key, ttl)
return variant_id
class BaseExp:
@staticmethod
def allocate_variant(device_id, experiment_id):
exp_details = get_experiment_by_id(experiment_id)
if exp_details.get('is_disabled'):
return {}
existing_variant_id = get_device_variant(device_id, experiment_id)
if existing_variant_id:
return get_variant_by_id(existing_variant_id)
variants = get_variants_by_experiment_id(experiment_id)
if not variants:
return {}
chosen_variant = random.choice(variants)
query = f"""
INSERT INTO device_experiments (device_id, experiment_id, variant_id)
VALUES ('{device_id}', '{experiment_id}', '{chosen_variant}')
"""
cursor = connection.cursor()
cursor.execute(query)
cursor.close()
chosen_variant_details = get_variant_by_id(chosen_variant)
return chosen_variant_details
class Exp1(BaseExp):
def allocate_variant(self, device_id, experiment_id):
variant = self.allocate_variant(device_id, experiment_id)
return variant
class Exp2(BaseExp):
def allocate_variant(self, device_id, experiment_id):
variant = self.allocate_variant(device_id, experiment_id)
return variant
class Exp3(BaseExp):
def allocate_variant(self, device_id, experiment_id):
variant = self.allocate_variant(device_id, experiment_id)
return variant
class Exp4(BaseExp):
def allocate_variant(self, device_id, experiment_id):
variant = self.allocate_variant(device_id, experiment_id)
return variant
class Exp5(BaseExp):
def allocate_variant(self, device_id, experiment_id):
variant = self.allocate_variant(device_id, experiment_id)
return variant
def launch(request):
data = request.GET.dict()
# Parameters coming in the request
user_id = data.get('user_id')
device_id = data.get('device_id')
platform = data.get('platform')
response = {}
if not device_id and not user_id:
return Response(
{
'error': {
'message': 'Cannot fetch config'
}
},
status=400
)
var1 = Exp1().allocate_variant(device_id, 1)
var2 = Exp2().allocate_variant(device_id, 2)
Exp3().allocate_variant(device_id, 3)
Exp4().allocate_variant(device_id, 4)
Exp5().allocate_variant(device_id, 5)
if var1 and var1.get('title', '') == "B":
response['detail_1'] = 'details1'
response['detail_2'] = True
if var2 and var2.get('title', '') == "B":
response['detail_1'] = 'details2'
response['detail_2'] = False
return response
"""
- launch() -> Very high latency API
- Number of redis calls per request is very high
- Redis get calls have high latencies
Redis Cluster -> Single cloud hosted redis cluster
"""
Editor is loading...
Leave a Comment