import json
import logging
from abc import ABC, abstractmethod
from typing import Optional
from olc.alg.alg_context import AlgContextBuilder
from olc.alg.alg_manager import OlcAlgManager
from olc.alg.flow.flow_alg import FlowAbstractAlgorithm
from olc.bean.match_wrapper import MatchWrapper
from olc.bean.olc_config_rule import FlowPolicy, AlgInstance
from olc.bean.tag_group import TagGroup
from olc.collector.collector_manager import OlcCollectorManager
from olc.limit.limiter import Limit
logger = logging.getLogger(__name__)
class AbsDynamicLimiter(Limit, ABC):
def __init__(self, wrapper: MatchWrapper[FlowPolicy]):
self._wrapper: MatchWrapper[FlowPolicy] = wrapper
self.flow_policy: FlowPolicy = wrapper.policy
self._cal_ins: Optional[AlgInstance] = wrapper.policy.calculate_alg
self._cal_alg: Optional[FlowAbstractAlgorithm] = (
OlcAlgManager.get_instance().get_flow_alg(self._cal_ins.alg_name)
)
self.group: TagGroup = wrapper.tag_group
self._rate: int = self.flow_policy.rate_limit
self._init_burst: int = self.flow_policy.burst_limit
self._pre_rate: int = self._rate
def refresh_rate_limiter(self):
"""
动态算法,刷新限速器
:return:
"""
try:
if self._cal_alg is None:
logger.warning(f"not found flow algorithm {self._cal_ins.alg_name}")
return
instance_paras = self._cal_ins.alg_param.copy()
for key, value in instance_paras.items():
alg_param = self._cal_alg.para_names.get(key)
if alg_param is not None:
if alg_param.dynamic:
true_value = OlcCollectorManager.get_instance().get_dyn_key_true_value(value)
if true_value is None:
logger.warning(f"get dynamic value err, dynamic key {value} is null")
return
instance_paras[key] = true_value
builder = AlgContextBuilder[float]().new_builder()
builder.set_group(self.group)
builder.set_policy(self.flow_policy)
builder.set_parameter(instance_paras)
builder.set_previous(self._rate)
builder.set_init_result(self._init_burst)
new_rate = self._cal_alg.make_decision(builder.build())
except Exception as e:
logger.warning(f"limit dynamic algorithm {self._cal_ins.alg_name} error: {e}")
self.update_rate(self._init_burst)
self._rate = self._init_burst
else:
logger.info(f"{self.group.name}, limit update:{new_rate}, paras: {json.dumps(instance_paras, indent=4)}")
self.update_rate(new_rate)
self._rate = new_rate
@abstractmethod
def update_rate(self, rate_limit: int) -> None:
"""
更新速率
:param rate_limit:
:return:
"""