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.
Files changed (84) hide show
  1. polaris/__init__.py +74 -0
  2. polaris/_version.py +16 -0
  3. polaris/api/__init__.py +55 -0
  4. polaris/api/_log_file.py +232 -0
  5. polaris/api/config.py +145 -0
  6. polaris/api/consumer.py +240 -0
  7. polaris/api/log.py +414 -0
  8. polaris/api/lossless.py +73 -0
  9. polaris/api/provider.py +152 -0
  10. polaris/api/skill.py +162 -0
  11. polaris/pkg/__init__.py +15 -0
  12. polaris/pkg/common/__init__.py +15 -0
  13. polaris/pkg/common/plugin.py +33 -0
  14. polaris/pkg/config/__init__.py +15 -0
  15. polaris/pkg/config/api.py +1205 -0
  16. polaris/pkg/config/default.py +92 -0
  17. polaris/pkg/config/event.py +76 -0
  18. polaris/pkg/config/loader.py +392 -0
  19. polaris/pkg/config/stat_reporter.py +100 -0
  20. polaris/pkg/flow/__init__.py +15 -0
  21. polaris/pkg/flow/admin_server.py +104 -0
  22. polaris/pkg/flow/async_flow.py +55 -0
  23. polaris/pkg/flow/base_flow.py +111 -0
  24. polaris/pkg/flow/impl.py +1277 -0
  25. polaris/pkg/flow/lossless.py +605 -0
  26. polaris/pkg/flow/notify.py +46 -0
  27. polaris/pkg/flow/register.py +210 -0
  28. polaris/pkg/flow/skill.py +110 -0
  29. polaris/pkg/flow/sync_flow.py +20 -0
  30. polaris/pkg/model/__init__.py +15 -0
  31. polaris/pkg/model/context.py +53 -0
  32. polaris/pkg/model/contract.py +89 -0
  33. polaris/pkg/model/core.py +51 -0
  34. polaris/pkg/model/engine.py +83 -0
  35. polaris/pkg/model/error.py +94 -0
  36. polaris/pkg/model/event.py +159 -0
  37. polaris/pkg/model/lossless.py +102 -0
  38. polaris/pkg/model/rule.py +152 -0
  39. polaris/pkg/model/server.py +288 -0
  40. polaris/pkg/model/service.py +820 -0
  41. polaris/pkg/model/skill.py +179 -0
  42. polaris/pkg/model/stat.py +168 -0
  43. polaris/pkg/model/util.py +58 -0
  44. polaris/pkg/version/__init__.py +18 -0
  45. polaris/plugin/__init__.py +32 -0
  46. polaris/plugin/circuit_breaker/__init__.py +19 -0
  47. polaris/plugin/circuit_breaker/base.py +54 -0
  48. polaris/plugin/circuit_breaker/composite.py +265 -0
  49. polaris/plugin/circuit_breaker/config.py +36 -0
  50. polaris/plugin/event/__init__.py +21 -0
  51. polaris/plugin/event/pushgateway.py +202 -0
  52. polaris/plugin/load_balancer/__init__.py +24 -0
  53. polaris/plugin/load_balancer/base.py +30 -0
  54. polaris/plugin/load_balancer/random.py +39 -0
  55. polaris/plugin/load_balancer/weighted_random.py +50 -0
  56. polaris/plugin/local_registry/__init__.py +18 -0
  57. polaris/plugin/local_registry/base.py +47 -0
  58. polaris/plugin/local_registry/file_cache.py +335 -0
  59. polaris/plugin/local_registry/local_cache.py +433 -0
  60. polaris/plugin/server_connector/__init__.py +20 -0
  61. polaris/plugin/server_connector/base.py +104 -0
  62. polaris/plugin/server_connector/convert.py +149 -0
  63. polaris/plugin/server_connector/grpc_connector/__init__.py +21 -0
  64. polaris/plugin/server_connector/grpc_connector/connection.py +401 -0
  65. polaris/plugin/server_connector/grpc_connector/grpc_client.py +384 -0
  66. polaris/plugin/server_connector/grpc_connector/tls.py +45 -0
  67. polaris/plugin/service_router/__init__.py +28 -0
  68. polaris/plugin/service_router/base.py +105 -0
  69. polaris/plugin/service_router/isolated.py +35 -0
  70. polaris/plugin/service_router/metadata.py +84 -0
  71. polaris/plugin/service_router/recover.py +62 -0
  72. polaris/plugin/service_router/util.py +54 -0
  73. polaris/plugin/skill/__init__.py +16 -0
  74. polaris/plugin/skill/connector.py +127 -0
  75. polaris/plugin/skill/persistence.py +94 -0
  76. polaris/plugin/stat_reporter/__init__.py +16 -0
  77. polaris/plugin/stat_reporter/base.py +34 -0
  78. polaris/plugin/stat_reporter/prometheus.py +375 -0
  79. polaris/plugin_manager.py +146 -0
  80. polaris_python-0.0.1.dev3.dist-info/METADATA +213 -0
  81. polaris_python-0.0.1.dev3.dist-info/RECORD +84 -0
  82. polaris_python-0.0.1.dev3.dist-info/WHEEL +5 -0
  83. polaris_python-0.0.1.dev3.dist-info/licenses/LICENSE +18 -0
  84. polaris_python-0.0.1.dev3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,433 @@
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
+ import asyncio
17
+ import threading
18
+
19
+ from ...pkg.model.service import ServiceInstances, Instance, new_service_instances, DefaultInstanceLocalValue
20
+ from ...pkg.model.server import InstanceDiscoverRequest
21
+ from ...pkg.model.rule import ServiceRule, new_simple_service_rule
22
+ from ...pkg.model.core import ServiceKey, ServiceEventKey, EventType
23
+ from ...pkg.config.api import get_server_services
24
+ from polaris.plugin_manager import PluginType, register_plugin, InitContext, \
25
+ EventType as PluginEventType
26
+ from .base import BaseLocalRegistry, InstanceFilter
27
+ from ...pkg.flow import impl
28
+ from polaris.pkg.model.error import ErrorCode, SDKError, ServerCode
29
+ import polaris.pkg.model.context as context
30
+ from polaris.pkg.model.event import SDKEventName, SDKEventType, now_event
31
+ from polaris.api.log import get_logger
32
+ from typing import Dict, Any, List
33
+ import time
34
+
35
+ logger = get_logger("cache")
36
+
37
+ PropertyCircuitBreakerStatus = "CircuitBreakerStatus"
38
+ EmptyRule = new_simple_service_rule(EventType.Unknown, None, "")
39
+
40
+
41
+ class CacheObject:
42
+ def __init__(self, invalid: bool = False):
43
+ self.invalid: bool = invalid
44
+ self.last_visit_time: float = time.monotonic()
45
+ self.value = None
46
+ self.remote_updated = False
47
+ self.lock = threading.RLock()
48
+ self.load_lock = asyncio.Lock()
49
+ self.loading = False
50
+
51
+ def is_remote_updated(self) -> bool:
52
+ """Report whether a remote discover response has replaced this snapshot."""
53
+ return self.remote_updated
54
+
55
+ def get_value(self, update_ts: bool):
56
+ if update_ts:
57
+ self.last_visit_time = time.monotonic()
58
+
59
+ return self.value
60
+
61
+ def set_value(self, value):
62
+ self.value = value
63
+
64
+
65
+ class InstanceProperties:
66
+ def __init__(self, service: ServiceKey = None, ID: str = "", properties: Dict[str, Any] = None):
67
+ self.service = service
68
+ self.ID = ID
69
+ if properties is None:
70
+ self.properties = {}
71
+ else:
72
+ self.properties = properties
73
+
74
+ def set_id(self, ID):
75
+ self.ID = ID
76
+
77
+ def set_property(self, property, value):
78
+ self.properties[property] = value
79
+
80
+
81
+ class ServiceUpdateRequest(ServiceKey):
82
+ def __init__(self, namespace: str = "", service: str = ""):
83
+ super(ServiceUpdateRequest, self).__init__(namespace=namespace, service=service)
84
+ self.properties: List[InstanceProperties] = []
85
+
86
+
87
+ class InstanceRegistry:
88
+ def get_instances(self, instance_filter: InstanceFilter):
89
+ pass
90
+
91
+ def load_instances(self, service: str, namespace: str):
92
+ pass
93
+
94
+ def update_instances(self, update_request: ServiceUpdateRequest):
95
+ pass
96
+
97
+ def get_services(self):
98
+ pass
99
+
100
+ # 配置获取的过滤器
101
+ class RuleFilter:
102
+ def __init__(self, service_event_key: ServiceEventKey):
103
+ self.service_event_key = service_event_key
104
+
105
+
106
+ async def load_file_cache(engine, request):
107
+ """Read one instance backup without using its modification time as a freshness gate."""
108
+ response = await engine.file_cache.async_get(request, expire=None)
109
+ if response is None:
110
+ return None
111
+ # Legacy snapshots did not always carry the response type, but must identify the service.
112
+ if (response.code.value != ServerCode.ExecuteSuccess
113
+ or response.type not in (0, request.type)
114
+ or response.service.name.value != request.name
115
+ or response.service.namespace.value != request.namespace):
116
+ logger.warning("ignore invalid file cache for %s/%s type %s", request.namespace, request.name, request.type)
117
+ return None
118
+ logger.debug("use file cache namespace=%s service=%s", request.namespace, request.name)
119
+ return response
120
+
121
+
122
+ @register_plugin(PluginType.LOCAL_CACHE, 'inmemory')
123
+ class LocalCache(BaseLocalRegistry):
124
+ def __init__(self, init_ctx: InitContext = None):
125
+ self.init_ctx = init_ctx
126
+ self.config = self.init_ctx.config
127
+ self._cache_lock = threading.RLock()
128
+ self.service_map: Dict[ServiceEventKey, CacheObject] = {}
129
+ self.services: Dict[ServiceEventKey, bool] = {}
130
+ self._watch_counts: Dict[ServiceEventKey, int] = {}
131
+ self._system_services = {
132
+ (cluster.service_key.namespace, cluster.service_key.service)
133
+ for cluster in get_server_services(self.config).values()
134
+ }
135
+
136
+ def get_instances(self, instance_filter: InstanceFilter) -> ServiceInstances:
137
+ """
138
+ 从缓存中获取实例
139
+ :param instance_filter: 过滤器
140
+ :return: ServiceInstances
141
+ """
142
+ service_key = ServiceEventKey(instance_filter.namespace, instance_filter.service, EventType.Instance)
143
+ with self._cache_lock:
144
+ cache_obj = self.service_map.get(service_key)
145
+ if cache_obj is None or cache_obj.invalid:
146
+ return None
147
+ value = cache_obj.get_value(not instance_filter.is_internal_request)
148
+ if value is None or (not cache_obj.remote_updated and not instance_filter.include_cache):
149
+ return None
150
+ return value
151
+
152
+ async def load_instances(self, service: str, namespace: str, use_discover_cache=True, timeout=None):
153
+ """
154
+ 通过service和namespace加载instance到缓存中
155
+ :param use_discover_cache:
156
+ :param service: 服务名
157
+ :param namespace: 命名空间
158
+ :return: None
159
+ """
160
+ service_key = ServiceEventKey(namespace, service, EventType.Instance)
161
+ await self._load_instances(service_key, use_discover_cache, timeout)
162
+
163
+ async def _discover(self):
164
+ pass
165
+
166
+ async def _load_instances(self, service_key: ServiceEventKey, use_discover_cache: bool = True, timeout=None):
167
+ while True:
168
+ with self._cache_lock:
169
+ cache_obj = self.service_map.get(service_key)
170
+ if cache_obj is None:
171
+ cache_obj = CacheObject()
172
+ self.service_map[service_key] = cache_obj
173
+ # Keep loads behind eviction cleanup before creating a new generation.
174
+ async with cache_obj.load_lock:
175
+ if self.service_map.get(service_key) is not cache_obj:
176
+ continue
177
+ if cache_obj.remote_updated and cache_obj.value is not None:
178
+ cache_obj.get_value(True)
179
+ return
180
+ cache_obj.loading = True
181
+ try:
182
+ await self._load_value(service_key, cache_obj, use_discover_cache, timeout)
183
+ cache_obj.get_value(True)
184
+ finally:
185
+ cache_obj.loading = False
186
+ return
187
+
188
+ def _service_instances(self, response, old_instances=None, loaded_from_file=False):
189
+ def create_local_value(instance):
190
+ event_handle_list = self.init_ctx.plugins.get_event_subscriber(PluginEventType.ON_LOCALVALUE_CREATED)
191
+ local_value = DefaultInstanceLocalValue()
192
+ for handle in event_handle_list:
193
+ handle.on_plugin_event(PluginEventType.ON_LOCALVALUE_CREATED, local_value)
194
+ return local_value
195
+
196
+ return ServiceInstances.new_from_discover_rsp(
197
+ response, create_local_value, old_instances=old_instances, loaded_from_file=loaded_from_file,
198
+ )
199
+
200
+ def _publish_resource_event(self, event_name, service_key, old_value, new_value):
201
+ event_center = self.init_ctx.value_ctx.core_map.get(context.ContextKeyEventCenter)
202
+ if event_center is None:
203
+ return
204
+ event_center.publish(now_event(
205
+ self.init_ctx.value_ctx.get_client_id(), SDKEventType.INSTANCE, event_name,
206
+ client_ip=self.config.get_global().get_api().get_bind_ip(),
207
+ namespace=service_key.namespace, service=service_key.service,
208
+ old_value=old_value, new_value=new_value,
209
+ ))
210
+
211
+ async def _load_value(self, service_key, cache_obj, use_discover_cache, timeout=None):
212
+ if service_key.event_type != EventType.Instance:
213
+ raise SDKError(ErrorCode.ErrCodeAPIInvalidArgument, "only instance resources are cached")
214
+ engine = self.init_ctx.value_ctx.get_value(context.ContextKeyEngine)
215
+ update_task = engine.update_task_set.get(service_key)
216
+ if update_task is None or update_task.cache_obj is not cache_obj:
217
+ interval = self.config.get_consumer().get_local_cache().service_refresh_interval
218
+ system = self.config.get_global().get_system()
219
+ for cluster in (system.get_discover_cluster(), system.get_health_check_cluster(),
220
+ system.get_monitor_cluster()):
221
+ if (service_key.namespace, service_key.service) == (cluster.namespace, cluster.service):
222
+ interval = cluster.refresh_interval
223
+ update_task = impl.ServiceUpdateTask(
224
+ service_key, cache_obj, interval,
225
+ int(time.time() * 1000),
226
+ )
227
+ engine.update_task_set[service_key] = update_task
228
+
229
+ req = InstanceDiscoverRequest(1, service_key.service, service_key.namespace)
230
+ old_value = cache_obj.value
231
+ if cache_obj.value is None:
232
+ disk = await load_file_cache(engine, req)
233
+ if disk is not None:
234
+ disk_value = self._service_instances(disk, loaded_from_file=True)
235
+ cache_obj.set_value(disk_value)
236
+ self._publish_resource_event(SDKEventName.ON_SERVICE_ADDED, service_key, None, disk_value)
237
+ old_value = disk_value
238
+ if cache_obj.value is not None:
239
+ req.revision = cache_obj.value.revision
240
+
241
+ client = engine.svc_connector
242
+ success_loaded = False
243
+ err = None
244
+ ret = None
245
+ api_config = self.config.get_global().get_api()
246
+ try:
247
+ # Reconnecting streams may never raise, so bound the entire initial remote wait.
248
+ async with asyncio.timeout((timeout or api_config.get_timeout()) / 1000):
249
+ for attempt in range(api_config.get_max_retry_times() + 1):
250
+ try:
251
+ ret = await client.discover(req, use_discover_cache)
252
+ except SDKError as e:
253
+ err = e
254
+ if e.server_code == ServerCode.NotFoundService:
255
+ raise
256
+ if e.err_code == ErrorCode.ErrCodeDataNotChange and cache_obj.value is not None:
257
+ cache_obj.remote_updated = True
258
+ self.services[service_key] = True
259
+ return
260
+ if e.err_code not in (ErrorCode.ErrCodeNetworkError, ErrorCode.ErrCodeAPITimeoutError):
261
+ raise
262
+ logger.error("Failed to do discover %s and retry: %s", service_key.__dict__, repr(e))
263
+ if attempt < api_config.get_max_retry_times():
264
+ await asyncio.sleep(api_config.get_retry_interval() / 1000)
265
+ continue
266
+ else:
267
+ success_loaded = True
268
+ engine.file_cache.save(req, ret)
269
+ break
270
+ except SDKError as error:
271
+ if error.server_code == ServerCode.NotFoundService:
272
+ await self.remove_service(service_key, cache_obj)
273
+ raise
274
+ except TimeoutError:
275
+ if err is None:
276
+ err = SDKError(ErrorCode.ErrCodeAPITimeoutError,
277
+ "Timed out loading %s/%s type %s" % (req.namespace, req.name, req.type))
278
+ logger.warning("%s", err)
279
+ if not success_loaded:
280
+ if err is None:
281
+ err = SDKError(ErrorCode.ErrCodeAPITimeoutError,
282
+ "Timed out loading %s/%s type %s" % (req.namespace, req.name, req.type))
283
+ raise err
284
+
285
+ new_value = self._service_instances(ret, old_instances=cache_obj.value)
286
+ cache_obj.set_value(new_value)
287
+ cache_obj.remote_updated = True
288
+ self.services[service_key] = True
289
+ log_loaded = logger.info if old_value is None else logger.debug
290
+ log_loaded(
291
+ "cache snapshot loaded namespace=%s service=%s revision=%s instances=%d",
292
+ service_key.namespace, service_key.service,
293
+ new_value.revision, len(new_value.instances),
294
+ )
295
+ self._publish_resource_event(
296
+ SDKEventName.ON_SERVICE_ADDED if old_value is None else SDKEventName.ON_SERVICE_UPDATED,
297
+ service_key, old_value, new_value,
298
+ )
299
+
300
+ async def remove_service(self, service_key, cache_obj):
301
+ """Delete one generation and its backup before allowing a replacement load."""
302
+ if self.service_map.get(service_key) is not cache_obj or cache_obj.invalid:
303
+ return
304
+ cache_obj.invalid = True
305
+ self.services.pop(service_key, None)
306
+ engine = self.init_ctx.value_ctx.get_value(context.ContextKeyEngine)
307
+ try:
308
+ await engine.stop_service_update(service_key, cache_obj)
309
+ finally:
310
+ if self.service_map.get(service_key) is cache_obj:
311
+ self.service_map.pop(service_key)
312
+ self._publish_resource_event(SDKEventName.ON_SERVICE_DELETED, service_key, cache_obj.value, None)
313
+
314
+ def get_service_revision(self, service, namespace, type):
315
+ service_key = ServiceEventKey(namespace, service, type)
316
+ cached_object = self.service_map.get(service_key, None)
317
+ if cached_object is None or cached_object.invalid or cached_object.value is None:
318
+ return None
319
+
320
+ return cached_object.value.revision
321
+
322
+ def update_instances(self, update_request: ServiceUpdateRequest):
323
+ """
324
+ 更新实例的本地信息
325
+ :param update_request:
326
+ :return:
327
+ """
328
+
329
+ service_key = ServiceEventKey(update_request.namespace, update_request.service, EventType.Instance)
330
+ cache_obj = self.service_map.get(service_key, None)
331
+ if cache_obj is None:
332
+ raise Exception("cache not exists in update_instances %s" % service_key.__dict__)
333
+
334
+ for p in update_request.properties:
335
+ service_instances = self.get_instances(InstanceFilter(p.service.namespace, p.service.service, True))
336
+ local_value = service_instances.get_instance_local_value(p.ID)
337
+ if local_value is None:
338
+ continue
339
+
340
+ for k, v in p.properties.items():
341
+ if k == PropertyCircuitBreakerStatus:
342
+ local_value.set_circuit_breaker_status(v)
343
+
344
+ def update_service(self, service_key: ServiceEventKey, service_instance: ServiceInstances):
345
+ cache_object = self.service_map.get(service_key, None)
346
+ if cache_object is None or cache_object.invalid:
347
+ logger.error("updating object that is not exist in cache %s", service_key.__dict__)
348
+ return False
349
+
350
+ with cache_object.lock:
351
+ old_value = cache_object.value
352
+ cache_object.set_value(service_instance)
353
+ cache_object.remote_updated = True
354
+ self._publish_resource_event(SDKEventName.ON_SERVICE_UPDATED, service_key, old_value, service_instance)
355
+ self.services[service_key] = True
356
+
357
+ return True
358
+
359
+ # 非阻塞获取配置信息
360
+ def get_service_rule(self, rule_filter: RuleFilter) -> ServiceRule:
361
+ with self._cache_lock:
362
+ cache_obj = self.service_map.get(rule_filter.service_event_key)
363
+ if cache_obj is None or cache_obj.invalid:
364
+ return EmptyRule
365
+ return cache_obj.get_value(True) or EmptyRule
366
+
367
+ def get_services(self):
368
+ return self.services.copy()
369
+
370
+ def watch_service(self, namespace: str, service: str):
371
+ """Pin one instance resource so idle eviction does not remove it."""
372
+ service_key = ServiceEventKey(namespace, service, EventType.Instance)
373
+ with self._cache_lock:
374
+ self._watch_counts[service_key] = self._watch_counts.get(service_key, 0) + 1
375
+ cache_obj = self.service_map.get(service_key)
376
+ if cache_obj is not None:
377
+ cache_obj.get_value(True)
378
+
379
+ def unwatch_service(self, namespace: str, service: str):
380
+ """Release one watch reference; eviction starts from the release time."""
381
+ service_key = ServiceEventKey(namespace, service, EventType.Instance)
382
+ with self._cache_lock:
383
+ count = self._watch_counts.get(service_key, 0)
384
+ if count <= 1:
385
+ self._watch_counts.pop(service_key, None)
386
+ else:
387
+ self._watch_counts[service_key] = count - 1
388
+ cache_obj = self.service_map.get(service_key)
389
+ if cache_obj is not None:
390
+ cache_obj.last_visit_time = time.monotonic()
391
+
392
+ def _is_expired(self, service_key, cache_obj, now):
393
+ if cache_obj.invalid or cache_obj.loading:
394
+ return False
395
+ if self._watch_counts.get(service_key, 0) > 0:
396
+ return False
397
+ if (service_key.namespace, service_key.service) in self._system_services:
398
+ return False
399
+ expire_time = self.config.get_consumer().get_local_cache().service_expire_time
400
+ return (now - cache_obj.last_visit_time) * 1000 >= expire_time
401
+
402
+ async def expire_services(self):
403
+ """Release idle resources and their discovery streams on the context owner loop."""
404
+ engine = self.init_ctx.value_ctx.get_value(context.ContextKeyEngine)
405
+ expired = []
406
+ for service_key, cache_obj in list(self.service_map.items()):
407
+ if not self._is_expired(service_key, cache_obj, time.monotonic()):
408
+ continue
409
+ async with cache_obj.load_lock:
410
+ with self._cache_lock:
411
+ if self.service_map.get(service_key) is not cache_obj:
412
+ continue
413
+ if not self._is_expired(service_key, cache_obj, time.monotonic()):
414
+ continue
415
+ cache_obj.invalid = True
416
+ self.services.pop(service_key, None)
417
+ try:
418
+ await engine.stop_service_update(service_key, cache_obj)
419
+ except Exception as error:
420
+ logger.error("failed to clean idle resource %s: %s", service_key.__dict__, error)
421
+ finally:
422
+ with self._cache_lock:
423
+ if self.service_map.get(service_key) is cache_obj:
424
+ self.service_map.pop(service_key)
425
+ self._publish_resource_event(SDKEventName.ON_SERVICE_DELETED, service_key, cache_obj.value, None)
426
+ expired.append(service_key)
427
+ logger.info("evicted idle cache resource %s", service_key.__dict__)
428
+ return expired
429
+
430
+ def destroy(self):
431
+ """Release this context's memory snapshots after its owner loop has stopped."""
432
+ self.service_map.clear()
433
+ self.services.clear()
@@ -0,0 +1,20 @@
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 .base import BaseServerConnector
17
+
18
+ from .grpc_connector import GrpcConnector
19
+
20
+ __all__ = ["BaseServerConnector", "GrpcConnector"]
@@ -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 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 abc import ABC, abstractmethod
17
+
18
+ from polarismesh_specification.api.v1.service_manage import response_pb2
19
+
20
+ from polaris.pkg.model.server import (
21
+ InstanceDeRegisterRequest,
22
+ InstanceDiscoverRequest,
23
+ InstanceHeartbeatRequest,
24
+ InstanceRegisterRequest,
25
+ InstanceRegisterResponse,
26
+ ReportClientRequest,
27
+ ReportClientResponse,
28
+ )
29
+ from polaris.pkg.model.service import GetOneInstanceRequest, InstancesResponse
30
+
31
+ __all__ = ["BaseServerConnector"]
32
+
33
+
34
+ class BaseServerConnector(ABC):
35
+ """
36
+ 同步注册服务
37
+ """
38
+
39
+ @abstractmethod
40
+ async def register_instance(self, request: InstanceRegisterRequest) -> InstanceRegisterResponse:
41
+ pass
42
+
43
+ """
44
+ 同步反注册
45
+ """
46
+
47
+ @abstractmethod
48
+ async def deregister_instance(self, request: InstanceDeRegisterRequest):
49
+ pass
50
+
51
+ """
52
+ 服务发现
53
+ """
54
+
55
+ @abstractmethod
56
+ async def discover(
57
+ self,
58
+ request: InstanceDiscoverRequest,
59
+ use_discover_cache: bool = True,
60
+ ) -> response_pb2.DiscoverResponse:
61
+ pass
62
+
63
+ @abstractmethod
64
+ async def stop_discover(self, request: InstanceDiscoverRequest) -> None:
65
+ """Release discovery state for one resource after its reader has stopped."""
66
+ pass
67
+
68
+ """
69
+ 心跳上报
70
+ """
71
+
72
+ @abstractmethod
73
+ async def heartbeat(self, request: InstanceHeartbeatRequest):
74
+ pass
75
+
76
+ """
77
+ 上报客户端
78
+ """
79
+
80
+ @abstractmethod
81
+ async def report_client(self, request: ReportClientRequest) -> ReportClientResponse:
82
+ pass
83
+
84
+ """
85
+ 单次服务发现
86
+ """
87
+ @abstractmethod
88
+ def get_one_instance(self, request: GetOneInstanceRequest) -> InstancesResponse:
89
+ pass
90
+
91
+ @abstractmethod
92
+ async def close(self) -> None:
93
+ """Release connector resources."""
94
+ pass
95
+
96
+ async def report_service_contract(self, request):
97
+ """Report a contract when the connector supports the specification RPC."""
98
+ from polaris.pkg.model.error import ErrorCode, SDKError
99
+ raise SDKError(ErrorCode.ErrCodePluginError, "service contract reporting is unsupported by this connector")
100
+
101
+ async def get_service_contract(self, request):
102
+ """Retrieve a contract when the connector supports the specification RPC."""
103
+ from polaris.pkg.model.error import ErrorCode, SDKError
104
+ raise SDKError(ErrorCode.ErrCodePluginError, "service contract retrieval is unsupported by this connector")