polaris-python 0.0.1.dev3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- polaris/__init__.py +74 -0
- polaris/_version.py +16 -0
- polaris/api/__init__.py +55 -0
- polaris/api/_log_file.py +232 -0
- polaris/api/config.py +145 -0
- polaris/api/consumer.py +240 -0
- polaris/api/log.py +414 -0
- polaris/api/lossless.py +73 -0
- polaris/api/provider.py +152 -0
- polaris/api/skill.py +162 -0
- polaris/pkg/__init__.py +15 -0
- polaris/pkg/common/__init__.py +15 -0
- polaris/pkg/common/plugin.py +33 -0
- polaris/pkg/config/__init__.py +15 -0
- polaris/pkg/config/api.py +1205 -0
- polaris/pkg/config/default.py +92 -0
- polaris/pkg/config/event.py +76 -0
- polaris/pkg/config/loader.py +392 -0
- polaris/pkg/config/stat_reporter.py +100 -0
- polaris/pkg/flow/__init__.py +15 -0
- polaris/pkg/flow/admin_server.py +104 -0
- polaris/pkg/flow/async_flow.py +55 -0
- polaris/pkg/flow/base_flow.py +111 -0
- polaris/pkg/flow/impl.py +1277 -0
- polaris/pkg/flow/lossless.py +605 -0
- polaris/pkg/flow/notify.py +46 -0
- polaris/pkg/flow/register.py +210 -0
- polaris/pkg/flow/skill.py +110 -0
- polaris/pkg/flow/sync_flow.py +20 -0
- polaris/pkg/model/__init__.py +15 -0
- polaris/pkg/model/context.py +53 -0
- polaris/pkg/model/contract.py +89 -0
- polaris/pkg/model/core.py +51 -0
- polaris/pkg/model/engine.py +83 -0
- polaris/pkg/model/error.py +94 -0
- polaris/pkg/model/event.py +159 -0
- polaris/pkg/model/lossless.py +102 -0
- polaris/pkg/model/rule.py +152 -0
- polaris/pkg/model/server.py +288 -0
- polaris/pkg/model/service.py +820 -0
- polaris/pkg/model/skill.py +179 -0
- polaris/pkg/model/stat.py +168 -0
- polaris/pkg/model/util.py +58 -0
- polaris/pkg/version/__init__.py +18 -0
- polaris/plugin/__init__.py +32 -0
- polaris/plugin/circuit_breaker/__init__.py +19 -0
- polaris/plugin/circuit_breaker/base.py +54 -0
- polaris/plugin/circuit_breaker/composite.py +265 -0
- polaris/plugin/circuit_breaker/config.py +36 -0
- polaris/plugin/event/__init__.py +21 -0
- polaris/plugin/event/pushgateway.py +202 -0
- polaris/plugin/load_balancer/__init__.py +24 -0
- polaris/plugin/load_balancer/base.py +30 -0
- polaris/plugin/load_balancer/random.py +39 -0
- polaris/plugin/load_balancer/weighted_random.py +50 -0
- polaris/plugin/local_registry/__init__.py +18 -0
- polaris/plugin/local_registry/base.py +47 -0
- polaris/plugin/local_registry/file_cache.py +335 -0
- polaris/plugin/local_registry/local_cache.py +433 -0
- polaris/plugin/server_connector/__init__.py +20 -0
- polaris/plugin/server_connector/base.py +104 -0
- polaris/plugin/server_connector/convert.py +149 -0
- polaris/plugin/server_connector/grpc_connector/__init__.py +21 -0
- polaris/plugin/server_connector/grpc_connector/connection.py +401 -0
- polaris/plugin/server_connector/grpc_connector/grpc_client.py +384 -0
- polaris/plugin/server_connector/grpc_connector/tls.py +45 -0
- polaris/plugin/service_router/__init__.py +28 -0
- polaris/plugin/service_router/base.py +105 -0
- polaris/plugin/service_router/isolated.py +35 -0
- polaris/plugin/service_router/metadata.py +84 -0
- polaris/plugin/service_router/recover.py +62 -0
- polaris/plugin/service_router/util.py +54 -0
- polaris/plugin/skill/__init__.py +16 -0
- polaris/plugin/skill/connector.py +127 -0
- polaris/plugin/skill/persistence.py +94 -0
- polaris/plugin/stat_reporter/__init__.py +16 -0
- polaris/plugin/stat_reporter/base.py +34 -0
- polaris/plugin/stat_reporter/prometheus.py +375 -0
- polaris/plugin_manager.py +146 -0
- polaris_python-0.0.1.dev3.dist-info/METADATA +213 -0
- polaris_python-0.0.1.dev3.dist-info/RECORD +84 -0
- polaris_python-0.0.1.dev3.dist-info/WHEEL +5 -0
- polaris_python-0.0.1.dev3.dist-info/licenses/LICENSE +18 -0
- polaris_python-0.0.1.dev3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Tencent is pleased to support the open source community by making polaris-python available.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2021 Tencent. All rights reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the BSD 3-Clause License (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# https://opensource.org/licenses/BSD-3-Clause
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
"""Shared admin HTTP server for stats and lossless endpoints."""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import time
|
|
22
|
+
|
|
23
|
+
from aiohttp import web
|
|
24
|
+
|
|
25
|
+
import polaris.api.log as logger
|
|
26
|
+
from polaris.pkg.config.stat_reporter import AdminConfig
|
|
27
|
+
from polaris.pkg.model.error import ErrorCode, SDKError
|
|
28
|
+
|
|
29
|
+
admin_logger = logger.get_logger("admin")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AdminHttpServer:
|
|
33
|
+
"""Expose one aiohttp application for every SDK component on the admin port."""
|
|
34
|
+
|
|
35
|
+
def __init__(self, admin_config: AdminConfig):
|
|
36
|
+
self.admin_config = admin_config
|
|
37
|
+
self.app = web.Application(middlewares=[self._log_request])
|
|
38
|
+
self.runner = None
|
|
39
|
+
self.port = None
|
|
40
|
+
self._routes = {}
|
|
41
|
+
self._started = False
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
@web.middleware
|
|
45
|
+
async def _log_request(request, handler):
|
|
46
|
+
started = time.monotonic()
|
|
47
|
+
try:
|
|
48
|
+
response = await handler(request)
|
|
49
|
+
except Exception as error:
|
|
50
|
+
admin_logger.error("admin http %s %s failed: %s", request.method, request.path, error)
|
|
51
|
+
raise
|
|
52
|
+
admin_logger.debug(
|
|
53
|
+
"admin http %s %s status=%d cost=%.3fms",
|
|
54
|
+
request.method, request.path, response.status, (time.monotonic() - started) * 1000,
|
|
55
|
+
)
|
|
56
|
+
return response
|
|
57
|
+
|
|
58
|
+
def add_route(self, method: str, path: str, handler) -> None:
|
|
59
|
+
key = (method, path)
|
|
60
|
+
if key in self._routes:
|
|
61
|
+
raise SDKError(ErrorCode.ErrCodeAPIInvalidArgument,
|
|
62
|
+
f"duplicated admin HTTP route {method} {path}")
|
|
63
|
+
self._routes[key] = handler
|
|
64
|
+
self.app.router.add_route(method, path, handler)
|
|
65
|
+
|
|
66
|
+
def has_routes(self) -> bool:
|
|
67
|
+
return bool(self._routes)
|
|
68
|
+
|
|
69
|
+
async def start(self) -> None:
|
|
70
|
+
"""Bind the configured admin address once all routes have been added."""
|
|
71
|
+
if self._started:
|
|
72
|
+
return
|
|
73
|
+
if not self._routes or self.admin_config.port is None or self.admin_config.port < 0:
|
|
74
|
+
admin_logger.info(
|
|
75
|
+
"admin http server disabled host=%s port=%s routes=%d",
|
|
76
|
+
self.admin_config.host, self.admin_config.port, len(self._routes),
|
|
77
|
+
)
|
|
78
|
+
return
|
|
79
|
+
self.runner = web.AppRunner(self.app, access_log=None)
|
|
80
|
+
await self.runner.setup()
|
|
81
|
+
site = web.TCPSite(self.runner, self.admin_config.host, self.admin_config.port)
|
|
82
|
+
try:
|
|
83
|
+
await site.start()
|
|
84
|
+
except OSError as error:
|
|
85
|
+
await self.runner.cleanup()
|
|
86
|
+
self.runner = None
|
|
87
|
+
raise SDKError(ErrorCode.ErrCodeAPIInvalidConfig,
|
|
88
|
+
f"Cannot bind admin listener {self.admin_config.host}:{self.admin_config.port}: {error}") from error
|
|
89
|
+
self.port = site._server.sockets[0].getsockname()[1]
|
|
90
|
+
self._started = True
|
|
91
|
+
admin_logger.info(
|
|
92
|
+
"admin http server listening host=%s port=%s routes=%d",
|
|
93
|
+
self.admin_config.host, self.port, len(self._routes),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
async def close(self) -> None:
|
|
97
|
+
started = self._started
|
|
98
|
+
if self.runner is not None:
|
|
99
|
+
await self.runner.cleanup()
|
|
100
|
+
self.runner = None
|
|
101
|
+
self._started = False
|
|
102
|
+
self.port = None
|
|
103
|
+
if started:
|
|
104
|
+
admin_logger.info("admin http server stopped")
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Tencent is pleased to support the open source community by making polaris-python available.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2021 Tencent. All rights reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the BSD 3-Clause License (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# https://opensource.org/licenses/BSD-3-Clause
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software distributed
|
|
12
|
+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
13
|
+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
14
|
+
# specific language governing permissions and limitations under the License.
|
|
15
|
+
|
|
16
|
+
from polaris.pkg.model.service import GetOneInstanceRequest, GetInstancesRequest
|
|
17
|
+
from polaris.pkg.flow.base_flow import CacheFilter, CacheResult
|
|
18
|
+
from polaris.pkg.flow.impl import Engine
|
|
19
|
+
from polaris.pkg.flow.base_flow import get_load_cache_values
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class FutureRequest:
|
|
23
|
+
def __init__(self, request: GetOneInstanceRequest, hash_value: int, do_load_balance: bool):
|
|
24
|
+
self.request = request
|
|
25
|
+
self.hash_value = hash_value
|
|
26
|
+
self.do_load_balance = do_load_balance
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AsyncFlowFuture:
|
|
30
|
+
def __init__(self, request: FutureRequest, filter_request: CacheFilter, redirect_times: int, engine: Engine):
|
|
31
|
+
self.request = request
|
|
32
|
+
self.filter_request = filter_request
|
|
33
|
+
self.redirect_times = redirect_times
|
|
34
|
+
self.engine = engine
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class AsyncEngine(Engine):
|
|
38
|
+
|
|
39
|
+
def create_async_flow_future(self, req: FutureRequest):
|
|
40
|
+
future = AsyncFlowFuture(request=req)
|
|
41
|
+
future.engine = AsyncEngine
|
|
42
|
+
return future
|
|
43
|
+
|
|
44
|
+
async def async_get_instances(self, req: GetInstancesRequest, do_balance: bool):
|
|
45
|
+
req = self.set_default_value_for_instances_request(req)
|
|
46
|
+
async_future = self.create_async_flow_future(req)
|
|
47
|
+
async_future.filter_request = self.instance_request_to_cache_filter(req=req, redirect_service=None)
|
|
48
|
+
request = async_future.filter_request
|
|
49
|
+
result = await get_load_cache_values(self.registry, request, True)
|
|
50
|
+
return result
|
|
51
|
+
|
|
52
|
+
async def async_get_one_instance(self, req: GetOneInstanceRequest):
|
|
53
|
+
instance_request = GetInstancesRequest(flow_id=req.flow_id, service=req.service, namespace=req.namespave,
|
|
54
|
+
timeout=req.timeout)
|
|
55
|
+
return await self.async_get_instances(instance_request, True)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Tencent is pleased to support the open source community by making polaris-python available.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2021 Tencent. All rights reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the BSD 3-Clause License (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# https://opensource.org/licenses/BSD-3-Clause
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software distributed
|
|
12
|
+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
13
|
+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
14
|
+
# specific language governing permissions and limitations under the License.
|
|
15
|
+
|
|
16
|
+
from polaris.plugin.local_registry.local_cache import InstanceFilter
|
|
17
|
+
from polaris.pkg.model.rule import ServiceRule
|
|
18
|
+
from polaris.pkg.model.service import ServiceInstances
|
|
19
|
+
from polaris.plugin.local_registry.local_cache import LocalCache
|
|
20
|
+
from polaris.pkg.model.core import ServiceKey
|
|
21
|
+
from polaris.plugin.local_registry.local_cache import ServiceUpdateRequest
|
|
22
|
+
from typing import Dict
|
|
23
|
+
from polaris.api.log import get_logger
|
|
24
|
+
import copy
|
|
25
|
+
from polaris.plugin.circuit_breaker.composite import CircuitBreakResult
|
|
26
|
+
from polaris.pkg.model.error import ErrorCode, SDKError
|
|
27
|
+
|
|
28
|
+
logger = get_logger("cache")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class RealTimeLimitTask:
|
|
32
|
+
def __init__(self, svc: ServiceKey = None, ins_id: str = None, host: str = None, port: int = None,
|
|
33
|
+
cb_name: str = None):
|
|
34
|
+
self.service_key = svc
|
|
35
|
+
self.instance_id = ins_id
|
|
36
|
+
self.host = host
|
|
37
|
+
self.port = port
|
|
38
|
+
self.cb_name = cb_name
|
|
39
|
+
|
|
40
|
+
def get_host(self):
|
|
41
|
+
return self.host
|
|
42
|
+
|
|
43
|
+
def get_port(self):
|
|
44
|
+
return self.port
|
|
45
|
+
|
|
46
|
+
def get_instance_id(self):
|
|
47
|
+
return self.instance_id
|
|
48
|
+
|
|
49
|
+
def get_service_key(self):
|
|
50
|
+
return self.service_key
|
|
51
|
+
|
|
52
|
+
def get_cb_name(self):
|
|
53
|
+
return self.cb_name
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class CacheFilter:
|
|
57
|
+
def __init__(self, namespace: str, service: str, dest_instance_fileter: InstanceFilter):
|
|
58
|
+
self.namespace = namespace
|
|
59
|
+
self.service = service
|
|
60
|
+
self.desc_instances_filter = dest_instance_fileter
|
|
61
|
+
|
|
62
|
+
def to_context_key(self):
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class CacheResult:
|
|
67
|
+
def __init__(self, source_route_rule: ServiceRule = None, dest_route_rule: ServiceRule = None,
|
|
68
|
+
dest_instances: ServiceInstances = None):
|
|
69
|
+
self.source_route_rule = source_route_rule
|
|
70
|
+
self.dest_route_rule = dest_route_rule
|
|
71
|
+
self.dest_instances = dest_instances
|
|
72
|
+
self.combineContext = ""
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
async def get_load_cache_values(registry: LocalCache, filters: CacheFilter, load: bool,
|
|
76
|
+
use_discover_cache=True, timeout=None) -> CacheResult:
|
|
77
|
+
result = CacheResult()
|
|
78
|
+
instances = registry.get_instances(instance_filter=filters.desc_instances_filter)
|
|
79
|
+
if instances and instances.is_initialized():
|
|
80
|
+
result.dest_instances = copy.copy(instances)
|
|
81
|
+
elif load:
|
|
82
|
+
logger.debug("miss local cache and begin to load remote value for %s",
|
|
83
|
+
filters.desc_instances_filter.__dict__)
|
|
84
|
+
try:
|
|
85
|
+
await registry.load_instances(filters.service, filters.namespace, use_discover_cache, timeout=timeout)
|
|
86
|
+
except SDKError as error:
|
|
87
|
+
if error.err_code not in (ErrorCode.ErrCodeNetworkError, ErrorCode.ErrCodeAPITimeoutError):
|
|
88
|
+
raise
|
|
89
|
+
fallback_filter = copy.copy(filters.desc_instances_filter)
|
|
90
|
+
fallback_filter.include_cache = True
|
|
91
|
+
instances = registry.get_instances(fallback_filter)
|
|
92
|
+
if instances is None:
|
|
93
|
+
raise
|
|
94
|
+
logger.warning("remote discovery unavailable; using local snapshot for %s/%s",
|
|
95
|
+
filters.namespace, filters.service)
|
|
96
|
+
else:
|
|
97
|
+
instances = registry.get_instances(instance_filter=filters.desc_instances_filter)
|
|
98
|
+
result.dest_instances = copy.copy(instances) if instances is not None else None
|
|
99
|
+
else:
|
|
100
|
+
return None
|
|
101
|
+
return result
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def build_instance_property(now, allowed_request: int, instances):
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def build_service_update_request(svc: ServiceKey, results: Dict[str, CircuitBreakResult]) -> ServiceUpdateRequest:
|
|
109
|
+
request = ServiceUpdateRequest(service=svc.get_service(), namespace=svc.get_namespace())
|
|
110
|
+
for cb_name, result in results.items():
|
|
111
|
+
pass
|