Esempio n. 1
0
    def _handle_frame_request(self, request):
        """ Handle the FRAME request from the client """
        frame = request.frame

        if (request.client_id not in self.client_env_map) or \
                (self.env_client_map[self.client_env_map[request.client_id]] != request.client_id):
            if self.configuration.verbosity > 3:
                self.logger.info(
                    f"Received frame with stale client c{request.client_id}")

            response = pb.MasterResponse(response=pb.MasterResponse.ERROR)
            self.request_socket.send(response.SerializeToString())
        elif frame.nonce != self.command_nonce:
            if self.configuration.verbosity > 2:
                self.logger.info(
                    f"Received frame with incorrect nonce from client c{request.client_id} ({frame.nonce, self.command_nonce})"
                )
            # Notify client of an error request
            response = pb.MasterResponse(response=pb.MasterResponse.SOFT_ERROR)
            self.request_socket.send(response.SerializeToString())
        else:
            # CORRECT FRAME RECEIVED
            environment_id = self.client_env_map[request.client_id]

            if self.configuration.verbosity > 3:
                self.logger.info(
                    f"Received frame with correct nonce from c{request.client_id}/e{environment_id}"
                )

            self.observation_buffer[
                environment_id] = numpy_util.deserialize_numpy(
                    frame.observation)
            self.reward_buffer[environment_id] = frame.reward
            self.done_buffer[environment_id] = frame.done
            self.info_buffer[environment_id] = pickle.loads(frame.info)

            if frame.done and self.configuration.reset_compensation:
                # Reset compensation, unregister the resetting environment
                if self.configuration.verbosity > 2:
                    self.logger.info(
                        f"Reset compensation: unregistering env c{request.client_id}/e{environment_id}"
                    )

                self._unregister_env(environment_id)

                response = pb.MasterResponse(response=pb.MasterResponse.RESET)
                self.request_socket.send(response.SerializeToString())

                self._send_wake_up_call()
            else:
                # Just confirm receipt, nothing more
                response = pb.MasterResponse(response=pb.MasterResponse.OK)
                self.request_socket.send(response.SerializeToString())
Esempio n. 2
0
    def _communication_loop(self):
        """
        Main function of the server. Actively listen for connections from the clients and
        respond to their requests
        """
        poll_status = dict(
            self.request_poller.poll(self.configuration.timeout * 1000))

        if poll_status:
            request = pb.MasterRequest()
            request.ParseFromString(self.request_socket.recv())

            if request.command != pb.MasterRequest.INITIALIZE and request.instance_id != self.instance_id:
                # Received request for the wrong server
                response = pb.MasterResponse(response=pb.MasterResponse.ERROR)
                self.request_socket.send(response.SerializeToString())
            else:
                if request.command == pb.MasterRequest.INITIALIZE:
                    self._handle_initialize_request()
                elif request.command == pb.MasterRequest.CONNECT:
                    self._handle_connect_request(request)
                elif request.command == pb.MasterRequest.FRAME:
                    self._handle_frame_request(request)
                elif request.command == pb.MasterRequest.HEARTBEAT:
                    self._handle_heartbeat_request(request)
                else:
                    raise ServerHandlerException(
                        f"Received unknown request: {request}")
Esempio n. 3
0
    def _send_heartbeat_request(self):
        """ Make a request to the server, checking if it's alive """
        try:
            poll_status = dict(
                self.request_poller.poll(self.configuration.timeout * 1000))

            if self.configuration.verbosity > 3:
                self.logger.info(
                    f"Worker {self.client_id} sending heartbeat..")

            if self.request_socket in poll_status and poll_status[
                    self.request_socket] == zmq.POLLOUT:
                request = pb.MasterRequest(
                    command=pb.MasterRequest.HEARTBEAT,
                    client_id=self.client_id,
                    instance_id=self.server_instance_id,
                )

                self.request_socket.send(request.SerializeToString())

                response = pb.MasterResponse()
                response.ParseFromString(self.request_socket.recv())

                if response.response == pb.MasterResponse.OK:
                    if self.configuration.verbosity > 3:
                        self.logger.info("Frame OK Response")
                    return True
                if response.response == pb.MasterResponse.RESET:
                    if self.configuration.verbosity > 3:
                        self.logger.info("Frame RESET Response")
                    self.is_initialized = False
                    self.environment_id = None
                    self.is_idle = None
                    return False
                if response.response == pb.MasterResponse.SOFT_ERROR:
                    if self.configuration.verbosity > 3:
                        self.logger.info("Frame SOFT_ERROR Response")
                    return True
                if response.response == pb.MasterResponse.ERROR:
                    if self.configuration.verbosity > 3:
                        self.logger.info("Frame ERROR Response")
                    self.reset_client()
                    return False
                else:
                    if self.configuration.verbosity > 3:
                        self.logger.info(
                            "Frame UNKNOWN Response: {}".format(response))
                    self.reset_client()
                    return False
            else:
                self.reset_client()
                return False

        except zmq.Again:
            self.reset_client()
            return False
Esempio n. 4
0
    def _handle_connect_request(self, request):
        """ Handle the CONNECT request from the client """
        if self.observation_space is None or self.action_space is None:
            self.observation_space, self.action_space = pickle.loads(
                request.connect_payload.spaces)

        if self.connected_clients < self.number_of_clients:
            # Accept new client
            new_environment_id = self._map_new_env(request.client_id)

            if self.last_command is not None:
                response = pb.MasterResponse(
                    # Encourage the client to send a reset frame straight away
                    response=pb.MasterResponse.OK_ENCOURAGE,
                    connect_response=pb.ConnectResponse(
                        environment_id=new_environment_id,
                        last_command=self.last_command))
            else:
                response = pb.MasterResponse(
                    response=pb.MasterResponse.OK,
                    connect_response=pb.ConnectResponse(
                        environment_id=new_environment_id))

            if self.configuration.verbosity > 1:
                self.logger.info(
                    f"Master: assigned client id c{request.client_id} to environment e{new_environment_id}"
                )

            if self.configuration.verbosity > 2:
                self.logger.info(f"Client env map: {self.client_env_map}")

            self.client_env_map[request.client_id] = new_environment_id
            self.env_client_map[new_environment_id] = request.client_id

            self.request_socket.send(response.SerializeToString())
        else:
            # Too many clients connected, ignore for now
            response = pb.MasterResponse(response=pb.MasterResponse.WAIT)
            self.request_socket.send(response.SerializeToString())
Esempio n. 5
0
    def _send_connect_request(self, payload):
        """ Register environment with the server """
        try:
            poll_status = dict(
                self.request_poller.poll(self.configuration.timeout * 1000))

            if self.request_socket in poll_status and poll_status[
                    self.request_socket] == zmq.POLLOUT:
                request = pb.MasterRequest(command=pb.MasterRequest.CONNECT,
                                           client_id=self.client_id,
                                           instance_id=self.server_instance_id,
                                           connect_payload=payload)

                self.request_socket.send(request.SerializeToString())

                response = pb.MasterResponse()
                response.ParseFromString(self.request_socket.recv())

                if response.response == pb.MasterResponse.OK:
                    if self.configuration.verbosity > 2:
                        self.logger.info(
                            f"Worker {self.client_id} CONNECT - OK")
                    self.environment_id = response.connect_response.environment_id
                    self.command_nonce = 0
                    return True
                if response.response == pb.MasterResponse.OK_ENCOURAGE:
                    if self.configuration.verbosity > 2:
                        self.logger.info(
                            f"Worker {self.client_id} CONNECT - OK ENCOURAGE")
                    self.environment_id = response.connect_response.environment_id
                    self.command_nonce = response.connect_response.last_command.nonce
                    return self._send_frame(self._perform_reset())
                elif response.response == pb.MasterResponse.WAIT:
                    if self.configuration.verbosity > 3:
                        self.logger.info(
                            f"Worker {self.client_id} received wait command - server is busy"
                        )

                    self.is_idle = True
                    self.idle_timestamp = time.time()

                    return False
                else:
                    self.reset_client()
                    return False
            else:
                self.reset_client()
                return False
        except zmq.Again:
            self.reset_client()
            return False
Esempio n. 6
0
    def _send_initialize_request(self):
        """ Request a name from the server """
        try:
            poll_status = dict(
                self.request_poller.poll(self.configuration.timeout * 1000))

            if self.request_socket in poll_status and poll_status[
                    self.request_socket] == zmq.POLLOUT:
                request = pb.MasterRequest(command=pb.MasterRequest.INITIALIZE)
                self.request_socket.send(request.SerializeToString())

                response = pb.MasterResponse()
                response.ParseFromString(self.request_socket.recv())

                if response.response == pb.MasterResponse.OK:
                    name_response = response.name_response

                    if name_response.server_version != self.configuration.server_version:
                        raise ClientInitializationException(
                            f"Server version {name_response.server_version} does not match client version "
                            f"{self.configuration.server_version}")

                    if self.configuration.verbosity > 1:
                        self.logger.info(
                            f"Initialization received: client id {name_response.client_id}"
                        )
                    self.environment_name = name_response.name
                    self.environment_seed = name_response.seed
                    self.client_id = name_response.client_id
                    self.server_instance_id = name_response.instance_id
                    self.reset_compensation = name_response.reset_compensation

                    return True
                else:
                    self.reset_client()
                    return False
            else:
                self.reset_client()
                return False
        except zmq.Again:
            self.reset_client()
            return False
Esempio n. 7
0
    def _handle_initialize_request(self):
        """ Handle the INITIALIZE request from the client """
        response = pb.MasterResponse(
            response=pb.MasterResponse.OK,
            name_response=pb.NameResponse(
                name=self.configuration.environment_name,
                seed=self.last_client_id_assigned,
                server_version=self.configuration.server_version,
                client_id=self.last_client_id_assigned,
                instance_id=self.instance_id,
                reset_compensation=self.configuration.reset_compensation))

        if self.configuration.verbosity > 0:
            self.logger.info(
                f"Master: assigned client id {self.last_client_id_assigned}")

        # Client ids are monotonically increasing
        self.last_client_id_assigned += 1

        self.request_socket.send(response.SerializeToString())
Esempio n. 8
0
    def _send_frame(self, frame):
        """ Send environment frame to the server """
        try:
            poll_status = dict(
                self.request_poller.poll(self.configuration.timeout * 1000))

            if self.configuration.verbosity > 3:
                self.logger.info(f"Worker {self.client_id} sending frame..")

            frame.nonce = self.command_nonce

            if self.request_socket in poll_status and poll_status[
                    self.request_socket] == zmq.POLLOUT:
                request = pb.MasterRequest(command=pb.MasterRequest.FRAME,
                                           client_id=self.client_id,
                                           instance_id=self.server_instance_id,
                                           frame=frame)

                self.request_socket.send(request.SerializeToString())

                poll_recv_status = dict(
                    self.request_poller.poll(self.configuration.timeout *
                                             1000))

                if self.request_socket in poll_recv_status and poll_recv_status[
                        self.request_socket] == zmq.POLLIN:
                    response = pb.MasterResponse()
                    response.ParseFromString(self.request_socket.recv())

                    if response.response == pb.MasterResponse.OK:
                        if self.configuration.verbosity > 3:
                            self.logger.info("Frame OK Response")
                        return True
                    if response.response == pb.MasterResponse.RESET:
                        if self.configuration.verbosity > 3:
                            self.logger.info("Frame RESET Response")
                        self.is_initialized = False
                        self.environment_id = None
                        self.is_idle = None
                        return False
                    if response.response == pb.MasterResponse.SOFT_ERROR:
                        if self.configuration.verbosity > 3:
                            self.logger.info("Frame SOFT_ERROR Response")
                        return True
                    else:
                        if self.configuration.verbosity > 3:
                            self.logger.info(
                                "Frame UNKNOWN Response: {}".format(response))
                        self.reset_client()
                        return False
                else:
                    if self.configuration.verbosity > 3:
                        self.logger.info("Frame response timeout receive")
                    self.reset_client()
                    return False
            else:
                if self.configuration.verbosity > 3:
                    self.logger.info("Frame response timeout send")
                self.reset_client()
                return False
        except zmq.Again:
            self.reset_client()
            return False
Esempio n. 9
0
 def _handle_heartbeat_request(self, _):
     """ Respond to the client that the server is alive """
     response = pb.MasterResponse(response=pb.MasterResponse.OK)
     self.request_socket.send(response.SerializeToString())