async def echo_handler(session: SocketSession, msg: object): if not session.is_client: await session.send_message(msg) logger.info("recv msg: %s" % msg) else: logger.info("client recv msg: %s" % msg) pass
async def _dispatch_actor_message_in_loop(actor: ActorBase): loop_id = _new_loop_id() context = actor.context assert context if context.loop_id != 0: return context.loop_id = loop_id loaded = False try: try: await actor.activate_async() loaded = True except Exception as e: logger.error( "Actor:%s/%s ActivateAsync Fail, Exception:%s, StackTrace:%s" % (actor.type_name, actor.uid, e, traceback.format_exc()) ) context.loop_id = 0 return while True: # 让出CPU给其他协程, 防止某些协程等待时间过长 await asyncio.sleep(0) o = cast( Tuple[weakref.ReferenceType[SocketSession], object], await context.pop_message(), ) if o is None: logger.info( "Actor:%s/%s exit message loop" % (actor.type_name, actor.uid) ) break session, msg = o[0]() if o[0] else None, o[1] if isinstance(msg, RpcRequest): context.reentrant_id = msg.reentrant_id await _dispatch_actor_rpc_request(actor, session, msg) else: await actor.dispatch_message(msg) except Exception as e: logger.error( "_dispatch_actor_message_loop, Exception:%s, StackTrace:%s" % (e, traceback.format_exc()) ) pass try: if loaded: await actor.deactivate_async() except Exception as e: logger.error( "Actor:%s/%s DeactivateAsync Fail, Exception:%s, StaceTrace:%s" % (actor.type_name, actor.uid, e, traceback.format_exc()) ) if context.loop_id == loop_id: context.reentrant_id = -1 context.loop_id = 0 logger.info("Actor:%s/%s loop:%d finished" % (actor.type_name, actor.uid, loop_id))
def remove_session(self, session_id: int): if session_id in self._session_dict: session = self._session_dict[session_id] if session: session.close() del self._session_dict[session_id] logger.info("SocketSessionManager.remove_session, SessionID:%d" % session_id)
def close(self): logger.info("TcpSession.close, SessionID:%d Address:%s" % (self.session_id, self._address)) self._stop = True try: self._writer.close() except: pass
async def patch_code(self, code: str) -> Tuple[str, Optional[Exception]]: try: logger.info("patch_code, %s" % code) exec(code) except Exception as e: logger.exception(e) return ("fail", e) return ("success", None)
async def qps(): last = 0 while True: await asyncio.sleep(1.0) v = finished if v - last > 0: logger.info("QPS:%d" % (v - last)) last = v
def _process_connect_success(session: SocketSession): if session: session.heart_beat(_last_process_message_time) logger.info("SocketSessionManager, SessionID:%d, ConnectSuccess" % session.session_id) else: logger.error("SocketSessionManager, SessionID:%d not found" % session.session_id)
def add_session(self, session: SocketSession): session_id = session.session_id if session_id in self._session_dict: return self._session_dict[session_id] = session logger.info( "SocketSessionManager.add_session, SessionID:%d, CodecID:%d" % (session_id, session.codec.codec_id))
def _try_delete_old_server(self, node: api.HostNodeInfo) -> bool: if self._config.address == node.address and self.server_id() > node.server_id: logger.info( "try_delete_old_server, OldServerID:%s Address:%s" % (node.server_id, node.address) ) asyncio.create_task(api.delete_server(node.server_id, node.address)) return True return False
async def client(): await asyncio.sleep(2.0) session = await TcpSocketSession.connect("127.0.0.1", 5555, codec_id) count = 0 while True: await asyncio.sleep(1.0) if session is not None: await session.send_message("hello world: %d" % count) logger.info("%d" % count) count += 1 pass
def remove_server(self, node: ServerNode): _membership_manager.remove_member(node.server_uid) try: self._on_remove_server(node) logger.info("PD RemoveServer, ServerID:%d, Address:%s:%s" % (node.server_uid, node.host, node.port)) except Exception as e: logger.error( "Placement.RemoveServer, ServerUID:%d, Exception:%s, StackTrace:%s" % (node.server_uid, e, traceback.format_exc())) pass
async def __gc_actors(cls, actors: Dict[ActorID, ActorBase]): current_time = time.time() need_remove: List[Tuple[ActorID, ActorBase]] = list() for actor_id, actor in actors.items(): if (not actor.context or current_time >= actor.context.last_message_time + actor.gc_time()): need_remove.append((actor_id, actor)) for actor_id, actor in need_remove: if actor.context: await actor.context.push_message(None) logger.info("gc_actors, Actor:%s/%s" % (actor.type_name, actor.uid)) actors.pop(actor_id)
def add_server(self, node: ServerNode): server = node _membership_manager.add_member(server) try: self._on_add_server(server) logger.info( "PD AddServer, ServerID:%d, Address:%s:%s, Desc:%s" % (server.server_uid, server.host, server.port, server.desc)) except Exception as e: logger.error( "Placement.AddServer, ServerUID:%d, Exception:%s, StackTrace:%s" % (node.server_uid, e, traceback.format_exc())) pass
async def _try_connect(self, node: ServerNode): try: session = await TcpSocketSession.connect(node.host, int(node.port), CODEC_RPC) if session is not None: node.set_session(session) logger.info("try_connect ServerID:%d, Host:%s:%s success" % (node.server_uid, node.host, node.port)) self.session = session except Exception as e: logger.error("try_connect ServerID:%d, Host:%s:%s, Exception:%s" % (node.server_uid, node.host, node.port, e)) pass
async def _try_update_load_loop(): impl = Placement.instance() last = 0 while True: await asyncio.sleep(10) try: v = _actor_manager.weight if last != v: logger.info("ActorWeight:%d" % v) last = v impl.set_load(last) except: pass
async def listen(self, port: int, codec_id: int): codec = _codec_manager.get_codec(codec_id) if codec is None: logger.error("listen port:%d failed, CodecID:%d not found" % (port, codec_id)) return async def callback(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): assert codec await self._handle_new_session(codec, reader, writer) try: await asyncio.start_server(callback, port=port, limit=WINDOW_SIZE) logger.info("listen port:%d CodecID:%d success" % (port, codec_id)) except Exception as e: logger.error("listen port:%d Exception:%s" % (port, e))
async def find_position(self, i_type: str, uid: object) -> Optional[ServerNode]: node = self.find_position_in_cache(i_type, uid) if node is not None and node.session is not None: return node resp = await api.find_actor_position(i_type, "%s" % uid, 0) if resp.error_code != 0: raise Exception("%s" % resp.error_msg) node = _membership.get_member(resp.server_id) if node is not None: self._lru_cache[(i_type, uid)] = node.server_uid logger.info( "FindActorPosition:%s/%s, ServerID:%s, Address:%s:%s" % (i_type, uid, node.server_uid, node.host, node.port) ) else: if (i_type, uid) in self._lru_cache: del self._lru_cache[(i_type, uid)] logger.info("FindActorPosition:%s/%s position not found" % (i_type, uid)) return node
async def _try_connect(cls, node: ServerNode): begin = time.time() try: session = await TcpSocketSession.connect( node.host, int(node.port), CODEC_RPC ) if session is not None: node.set_session(session) logger.info( "try_connect ServerID:%d, Host:%s:%s success" % (node.server_uid, node.host, node.port) ) except Exception as e: end = time.time() logger.error( "try_connect ServerID:%d, Host:%s:%s, CostTime:%sms, Exception:%s" % (node.server_uid, node.host, node.port, int((end - begin) * 1000), e) ) pass
async def process_gateway_account_login(session: SocketSession, msg: object): global _config if not _config: _config = koala_config.get_config() request = cast(RpcMessage, msg) req = cast(RequestAccountLogin, request.meta) body = request.body body_message, check_sum = utils.message_check_sum( body, private_key=_config.private_key) logger.info( "process_gateway_account_login, SessionID:%s, OpenID:%s, ServerUD:%s , CheckSum:%s, %s" % (req.session_id, req.open_id, req.server_id, check_sum, body_message)) resp = ResponseAccountLogin() resp.session_id = req.session_id resp.actor_type = body_message.get("actor_type", "IPlayer") resp.actor_id = body_message.get("actor_id", "1") await session.send_message(RpcMessage(meta=resp))
async def register_server(self): resp = await api.new_server_id() if resp.error_code == 0: self._server_id = resp.id logger.info("PD Register Server Success, ServerID:%d" % self._server_id) else: logger.error( "PD Register Server Fail, ExitCode:%d" % ERROR_PD_NEW_SERVER.code ) exit(ERROR_PD_NEW_SERVER.code) return resp = await api.register_server( self._server_id, self._config.start_time, self._config.ttl, self._config.address, self._config.services, self._config.desc if self._config.desc else "host_%s" % self.server_id(), ) if resp.error_code == 0: self._lease_id = resp.lease_id logger.info("ServerID:%d, LeaseID:%d" % (self._server_id, self._lease_id)) service_list = [ "%s => %s" % (k, self._config.services[k]) for k in self._config.services ] logger.info("Host Services:%s" % (", ".join(service_list))) asyncio.create_task(self._heart_beat_loop()) else: logger.error( "%d, %s" % (ERROR_PD_NEW_SERVER.code, ERROR_PD_NEW_SERVER.message) ) exit(ERROR_PD_REGISTER_SERVER.code) pass
async def patch_code(): await asyncio.sleep(3.0) placement = Placement.instance() servers = placement.get_all_servers() for server in servers: proxy = rpc_proxy.get_rpc_proxy(hotfix.IHotFix, "1", server_node=server, check_postion=False) await proxy.patch_code("print(112233)") PORT = 15555 placement = SelfHostedPlacement(PORT) Placement.set_instance(placement) logger.info(Placement.instance()) koala_host.init_server(globals()) koala_host.listen_rpc(PORT) koala_host.create_task(service_1()) for item in range(16): i = item koala_host.create_task(bench(i)) koala_host.create_task(patch_code()) koala_host.create_task(run_timer(1)) koala_host.create_task(qps()) koala_host.run_server()
def set_instance(cls, impl: "Placement"): cls.__placement_impl = impl logger.info("init placement impl %s" % cls.__placement_impl)
async def say_hello(self, hello: str) -> str: service_2 = self.get_proxy(IService2, "2") logger.info( "service 2 return %s" % await service_2.hello(self.uid, random.randrange(0, 10000))) return "my name is %s, and yours is %s" % (self.uid, hello)
async def on_session_aborted(self, msg: NotifyActorSessionAborted): _ = msg logger.info("Actor:%s/%s SessionID:%s aborted" % (self.type_name, self.uid, self.session_id)) self.set_session_id(0)
async def on_new_session(self, msg: NotifyNewActorSession, body: bytes): _ = body logger.info("Actor:%s/%s NewSessionID:%s" % (self.type_name, self.uid, msg.session_id)) self.set_session_id(msg.session_id) pass
async def service_1(): await asyncio.sleep(3.0) proxy = rpc_proxy.get_rpc_proxy(IService1, "1") logger.info(await proxy.say_hello("2")) pass
def on_session_changed(self, old_session_id: int): logger.info( "Actor:%s/%s, OldSessionID:%s, NewSessionID:%s" % (self.type_name, self.uid, old_session_id, self.session_id))
def f(timer: ActorTimer): logger.info("timer, tick:%s" % timer.tick_count) if timer.tick_count >= count: a: BenchImpl = cast(BenchImpl, weak_actor()) a.unregister_timer(timer.timer_id)