-
Notifications
You must be signed in to change notification settings - Fork 1
Refactor Service.py #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 使用Handler解决了长串if else的问题,但是没有解决if else 可能存在遗漏的问题。例如,增加了一个新枚举但是忘记创建Handler的情况仍然存在。由于被分散到不同的文件,遗漏的可能性甚至增加了 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| from python_package._321CQU.service import ServiceEnum | ||
| from abc import ABC, abstractmethod | ||
| from micro_services_protobuf.notification_center import service_pb2_grpc as notification_grpc | ||
| from micro_services_protobuf.mycqu_service import mycqu_service_pb2_grpc as mycqu_grpc | ||
| from micro_services_protobuf.edu_admin_center import eac_service_pb2_grpc as eac_grpc | ||
| from micro_services_protobuf.course_score_query import service_pb2_grpc as csq_grpc | ||
| from micro_services_protobuf.control_center import control_center_service_pb2_grpc as cc_grpc | ||
|
|
||
|
|
||
| class ServiceHandler(ABC): | ||
| """ | ||
| 服务处理器抽象类 | ||
| """ | ||
|
|
||
| @abstractmethod | ||
| def support(self, name: ServiceEnum) -> bool: | ||
| """ | ||
| 判断是否支持该服务 | ||
| @param name: 服务名枚举 | ||
| """ | ||
| pass | ||
|
|
||
| @abstractmethod | ||
| @property | ||
| def get_service_name(self) -> str: | ||
| """ | ||
| 获取服务名 | ||
| """ | ||
| pass | ||
|
|
||
| @abstractmethod | ||
| def get_stub_class(self): | ||
| """ | ||
| 获取stub类 | ||
| """ | ||
| pass | ||
|
|
||
|
|
||
| class WechatManagerHandler(ServiceHandler): | ||
| """ | ||
| 微信管理器服务处理器 | ||
| """ | ||
|
|
||
| def support(self, name: ServiceEnum) -> bool: | ||
| return name == ServiceEnum.WechatManager | ||
|
|
||
| def get_service_name(self) -> str: | ||
| return 'wechat_manager' | ||
|
|
||
| def get_stub_class(self): | ||
| pass | ||
|
|
||
|
|
||
| class ApnsServiceHandler(ServiceHandler): | ||
| """ | ||
| Apns服务处理器 | ||
| """ | ||
|
|
||
| def support(self, name: ServiceEnum) -> bool: | ||
| return name == ServiceEnum.ApnsService | ||
|
|
||
| def get_service_name(self) -> str: | ||
| return 'notification_center' | ||
|
|
||
| def get_stub_class(self): | ||
| return notification_grpc.ApnsStub | ||
|
|
||
|
|
||
| class WechatServiceHandler(ServiceHandler): | ||
| """ | ||
| 微信服务处理器 | ||
| """ | ||
|
|
||
| def support(self, name: ServiceEnum) -> bool: | ||
| return name == ServiceEnum.WechatService | ||
|
|
||
| def get_service_name(self) -> str: | ||
| return 'notification_center' | ||
|
|
||
| def get_stub_class(self): | ||
| return notification_grpc.WechatStub | ||
|
|
||
|
|
||
| class NotificationServiceHandler(ServiceHandler): | ||
| """ | ||
| 通知服务处理器 | ||
| """ | ||
|
|
||
| def support(self, name: ServiceEnum) -> bool: | ||
| return name == ServiceEnum.NotificationService | ||
|
|
||
| def get_service_name(self) -> str: | ||
| return 'notification_center' | ||
|
|
||
| def get_stub_class(self): | ||
| return notification_grpc.NotificationStub | ||
|
|
||
|
|
||
| class ImportantInfoServiceHandler(ServiceHandler): | ||
| """ | ||
| 重要信息服务处理器 | ||
| """ | ||
|
|
||
| def support(self, name: ServiceEnum) -> bool: | ||
| return name == ServiceEnum.ImportantInfoService | ||
|
|
||
| def get_service_name(self) -> str: | ||
| return 'important_info' | ||
|
|
||
| def get_stub_class(self): | ||
| return cc_grpc.ImportantInfoServiceStub | ||
|
|
||
|
|
||
| class MycquServiceHandler(ServiceHandler): | ||
| """ | ||
| Mycqu服务处理器 | ||
| """ | ||
|
|
||
| def support(self, name: ServiceEnum) -> bool: | ||
| return name == ServiceEnum.MycquService | ||
|
|
||
| def get_service_name(self) -> str: | ||
| return 'mycqu' | ||
|
|
||
| def get_stub_class(self): | ||
| return mycqu_grpc.MycquFetcherStub | ||
|
|
||
|
|
||
| class CardServiceHandler(ServiceHandler): | ||
| """ | ||
| 一卡通服务处理器 | ||
| """ | ||
|
|
||
| def support(self, name: ServiceEnum) -> bool: | ||
| return name == ServiceEnum.CardService | ||
|
|
||
| def get_service_name(self) -> str: | ||
| return 'mycqu' | ||
|
|
||
| def get_stub_class(self): | ||
| return mycqu_grpc.CardFetcherStub | ||
|
|
||
|
|
||
| class LibraryServiceHandler(ServiceHandler): | ||
| """ | ||
| 图书馆服务处理器 | ||
| """ | ||
|
|
||
| def support(self, name: ServiceEnum) -> bool: | ||
| return name == ServiceEnum.LibraryService | ||
|
|
||
| def get_service_name(self) -> str: | ||
| return 'mycqu' | ||
|
|
||
| def get_stub_class(self): | ||
| return mycqu_grpc.LibraryFetcherStub | ||
|
|
||
|
|
||
| class EduAdminCenterHandler(ServiceHandler): | ||
| """ | ||
| 教务中心服务处理器 | ||
| """ | ||
|
|
||
| def support(self, name: ServiceEnum) -> bool: | ||
| return name == ServiceEnum.EduAdminCenter | ||
|
|
||
| def get_service_name(self) -> str: | ||
| return 'edu_admin_center' | ||
|
|
||
| def get_stub_class(self): | ||
| return eac_grpc.EduAdminCenterStub | ||
|
|
||
|
|
||
| class CourseScoreQueryHandler(ServiceHandler): | ||
| """ | ||
| 课程成绩查询服务处理器 | ||
| """ | ||
|
|
||
| def support(self, name: ServiceEnum) -> bool: | ||
| return name == ServiceEnum.CourseScoreQuery | ||
|
|
||
| def get_service_name(self) -> str: | ||
| return 'course_score_query' | ||
|
|
||
| def get_stub_class(self): | ||
| return csq_grpc.CourseScoreQueryStub |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,10 +9,13 @@ | |
| __all__ = ['gRPCManager', 'MockGRPCManager'] | ||
|
|
||
| from ..service import ServiceEnum | ||
| from ..service_handler import ServiceHandler | ||
|
|
||
|
|
||
| class gRPCManager(metaclass=Singleton): | ||
| def __init__(self, handler: ConfigHandler = _CONFIG_HANDLER): | ||
| # 初始化时创建每个ServiceHandler子类的实例 | ||
| self.service_instances = [cls() for cls in ServiceHandler.__subclasses__()] | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 不是所有服务都是使用gRPC进行编写的,考虑在这里通过is_http_service过滤不必要的实例;其次,反复调用子类构造方法会造成不必要的变量创建,ServiceEnum实际上的作用是将可用服务(如名称、所属配置文件)转化为枚举便于穷举和避免编写错误,起到了“配置”的作用,gRPC则通过“配置”创建服务的stub。既然是配置,那应该是唯一的,类似于单例,创建多个Handler实例指向唯一的“配置”似乎较为冗余。一种可行的方案是,为ServiceHandler创建一个私有类属性和一个静态方法,该静态方法接受一个filter(当前可以是简单的bool值,区分gRPC和http服务),在类属性为None时先获取所有实例并赋值给类属性,类属性有值时使用filter过滤不必要的实例回传以替代该方法,参考如下: 注意,上述代码中的is_http_service方法由于当前代码使用Handler类而非ServiceEnum,需要考虑其他实现 |
||
| all_options = handler.get_options('ServiceSetting') | ||
|
|
||
| service_hosts = list(filter(lambda x: x.endswith('_service_host'), all_options)) | ||
|
|
@@ -31,22 +34,26 @@ def __init__(self, handler: ConfigHandler = _CONFIG_HANDLER): | |
| }) | ||
|
|
||
| def get_service_config(self, service: ServiceEnum) -> Tuple[str, str]: | ||
| return (self._service_host[service.service_name + "_service_host"], | ||
| self._service_ports[service.service_name + "_service_port"]) | ||
| for instance in self.service_instances: | ||
| if instance.support(name=service): | ||
| return (self._service_host[instance.get_service_name + "_service_host"], | ||
| self._service_ports[instance.get_service_name + "_service_port"]) | ||
|
Comment on lines
+37
to
+40
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 未过滤Handler实例会在此处引入异常,可能会试图为http服务获取gRPC调用的配置(当然,之前的实现也存在这个问题) |
||
|
|
||
| @asynccontextmanager | ||
| async def get_stub(self, service: ServiceEnum): | ||
| if service.is_http_service: | ||
| raise RuntimeError("该服务不是gRPC服务") | ||
|
|
||
| target = service._get_stub_class() | ||
|
|
||
| if target is not None: | ||
| host = self._service_host[service.service_name + "_service_host"] | ||
| port = self._service_ports[service.service_name + "_service_port"] | ||
| target_url = host + ":" + port | ||
| async with insecure_channel(target_url) as channel: | ||
| yield target(channel) | ||
| for instance in self.service_instances: | ||
| if instance.support(name=service): | ||
|
Comment on lines
+46
to
+47
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 同前,可能会为http服务创建gRPC的stub |
||
| target = instance.get_stub_class() | ||
| if target is not None: | ||
| host = self._service_host[instance.get_service_name + "_service_host"] | ||
| port = self._service_ports[instance.get_service_name + "_service_port"] | ||
| target_url = host + ":" + str(port) | ||
| async with insecure_channel(target_url) as channel: | ||
| yield target(channel) | ||
| else: | ||
| raise RuntimeError("未提供对应服务Stub") | ||
|
|
||
|
|
||
| class MockGRPCManager(gRPCManager): | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 参照gRPCManager.py中的建议修改 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
service_name是公开的属性,在未对所有可能使用此方法的代码进行检查前最好不要直接删除该属性(保证API稳定性),而是考虑保留该属性的方案