Пример #1
0
    def __init__(self, g_pool, node_name=None, sync_group_prefix='default', base_bias=1.):
        super().__init__(g_pool)
        self.sync_group_prefix = sync_group_prefix
        self.discovery = None

        self.leaderboard = []
        self.has_been_master = 0.
        self.has_been_synced = 0.
        self.tie_breaker = random.random()
        self.base_bias = base_bias

        self.master_service = Clock_Sync_Master(self.g_pool.get_timestamp)
        self.follower_service = None  # only set if there is a better server than us

        self.restart_discovery(node_name)
Пример #2
0
def run_time_sync_master(group):

    pts_group = group + '-time_sync-v1'

    # the time source in the example is python time.time you can change this.
    # replace with an implementation that give your custom time in floating sec.
    clock_service = Clock_Sync_Master(time)

    # This example is a clock service only, not a clock follower.
    # Therefore the rank is designed to always trump all others.
    rank = 1000
    discovery = Pyre('pupil-helper-service')
    discovery.join(pts_group)
    discovery.start()
    logger.info('Joining "{}" group with rank {}'.format(pts_group, rank))

    def announce_clock_service_info():
        discovery.shout(
            pts_group,
            [repr(rank).encode(),
             repr(clock_service.port).encode()])

    try:
        for event in discovery.events():
            if event.type == 'JOIN' and event.group == pts_group:
                logger.info(
                    '"{}" joined "{}" group. Announcing service.'.format(
                        event.peer_name, pts_group))
                announce_clock_service_info()
    except KeyboardInterrupt:
        pass
    finally:
        logger.info('Leaving "{}" group'.format(pts_group))
        discovery.leave(pts_group)
        discovery.stop()
        clock_service.stop()
Пример #3
0
    def thread_loop(self, context, pipe):
        n = Pyre(self.name)
        n.join(self.group)
        n.start()
        poller = zmq.Poller()
        poller.register(pipe, zmq.POLLIN)
        poller.register(n.socket(), zmq.POLLIN)

        front, back = zhelper.zcreate_pipe(context)
        poller.register(back, zmq.POLLIN)

        def wake_up():
            #on app close this timer calls a closed socket. We simply catch it here.

            try:
                front.send('wake_up')
            except Exception as e:
                logger.debug('Orphaned timer thread raised error: %s' % e)

        t = Timer(self.time_sync_announce_interval, wake_up)
        t.daemon = True
        t.start()

        while (True):
            try:
                #this should not fail but it does sometimes. We need to clean this out.
                # I think we are not treating sockets correclty as they are not thread-save.
                items = dict(poller.poll())
            except zmq.ZMQError:
                logger.warning('Socket fail.')
                continue

            if back in items and items[back] == zmq.POLLIN:
                back.recv()
                #timeout events are used for pupil sync.
                #annouce masterhood every interval time:
                if isinstance(self.time_sync_node, Clock_Sync_Master):
                    n.shouts(
                        self.group, SYNC_TIME_MASTER_ANNOUNCE +
                        "%s" % self.clock_master_worthiness() + msg_delimeter +
                        '%s' % self.time_sync_node.port)

                # synced slave: see if we should become master if we dont hear annoncement within time.
                elif isinstance(self.time_sync_node, Clock_Sync_Follower
                                ) and not self.time_sync_node.offset_remains:
                    if self.get_unadjusted_time(
                    ) - self.last_master_announce > self.time_sync_wait_interval_short:
                        self.time_sync_node.terminate()
                        self.time_sync_node = Clock_Sync_Master(
                            time_fn=self.get_time)
                        n.shouts(
                            self.group, SYNC_TIME_MASTER_ANNOUNCE +
                            "%s" % self.clock_master_worthiness() +
                            msg_delimeter + '%s' % self.time_sync_node.port)

                # unsynced slave or none should wait longer but eventually take over
                elif self.get_unadjusted_time(
                ) - self.last_master_announce > self.time_sync_wait_interval_long:
                    if self.time_sync_node:
                        self.time_sync_node.terminate()
                    self.time_sync_node = Clock_Sync_Master(
                        time_fn=self.get_time)
                    n.shouts(
                        self.group, SYNC_TIME_MASTER_ANNOUNCE +
                        "%s" % self.clock_master_worthiness() + msg_delimeter +
                        '%s' % self.time_sync_node.port)

                t = Timer(self.time_sync_announce_interval, wake_up)
                t.daemon = True
                t.start()

            if pipe in items and items[pipe] == zmq.POLLIN:
                message = pipe.recv()
                # message to quit
                if message.decode('utf-8') == exit_thread:
                    break
                else:
                    logger.debug("Shout '%s' to '%s' " % (message, self.group))
                    n.shouts(self.group, message)
            if n.socket() in items and items[n.socket()] == zmq.POLLIN:
                cmds = n.recv()
                msg_type = cmds.pop(0)
                msg_type = msg_type.decode('utf-8')
                if msg_type == "SHOUT":
                    uuid, name, group, msg = cmds
                    logger.debug("'%s' shouts '%s'." % (name, msg))
                    self._handle_msg(uuid, name, msg, n)

                elif msg_type == "WHISPER":
                    uuid, name, msg = cmds
                    logger.debug("'%s/' whispers '%s'." % (name, msg))
                    self._handle_msg_whisper(uuid, name, msg, n)

                elif msg_type == "JOIN":
                    uuid, name, group = cmds
                    if group == self.group:
                        self.group_members[uuid] = name
                        self.update_gui()

                elif msg_type == "EXIT":
                    uuid, name = cmds
                    try:
                        del self.group_members[uuid]
                    except KeyError:
                        pass
                    else:
                        self.update_gui()

                # elif msg_type == "LEAVE":
                #     uuid,name,group = cmds
                # elif msg_type == "ENTER":
                #     uuid,name,headers,ip = cmds
                #     logger.warning((uuid,'name',headers,ip))
            else:
                pass

        logger.debug('thread_loop closing.')

        self.thread_pipe = None
        n.stop()
Пример #4
0
    def on_notify(self, notification):
        """Synchronize time of Actors across local network.

        The notification scheme is used to handle interal timing
        and to talk to remote pers via the `Pupil_Groups` plugin.

        Reacts to notifications:
            ``time_sync.master_announcement``: React accordingly to annouce notification from remote peer.
            ``time_sync.master_announce_interval``: Re-annouce clock masterhood.
            ``time_sync.master_announce_timeout``: React accordingly when no master announcement has appeard whithin timeout.


        Emits notifications:
            ``time_sync.master_announcement``: Announce masterhood to remote peers (remote notification).
            ``time_sync.master_announce_interval``: Re-announce masterhood reminder (delayed notification).
            ``time_sync.master_announce_timeout``:  Timeout for foreind master announcement (delayed notification).

        """
        if notification['subject'].startswith('time_sync.master_announcement'):
            if self.is_master:
                if notification['worthiness'] > self.clock_master_worthiness():
                    #We need to yield.
                    self.time_sync_node.stop()
                    self.time_sync_node = None
                else:
                    #Denounce the lesser competition.
                    n = {
                        'subject': 'time_sync.master_announcement',
                        'host': self.time_sync_node.host,
                        'port': self.time_sync_node.port,
                        'worthiness': self.clock_master_worthiness(),
                        'remote_notify': 'all'
                    }
                    self.notify_all(n)

            if self.is_follower:
                # update follower info
                self.time_sync_node.host = notification['host']
                self.time_sync_node.port = notification['port']

            if self.is_nothing:
                # Create follower.
                logger.debug("Clock will sync with {}".format(
                    notification['host']))
                self.time_sync_node = Clock_Sync_Follower(
                    notification['host'],
                    port=notification['port'],
                    interval=10,
                    time_fn=self.get_time,
                    jump_fn=self.jump_time,
                    slew_fn=self.slew_time)

            if not self.is_master:
                #(Re)set the timer.
                self.notify_all(self.master_announce_timeout_notification)

        elif notification['subject'].startswith(
                'time_sync.master_announce_timeout'):
            if self.is_master:
                pass
            else:
                #We have not heard from a master in too long.
                logger.info("Elevate self to clock master.")
                self.time_sync_node = Clock_Sync_Master(
                    self.g_pool.get_timestamp)
                n = {
                    'subject': 'time_sync.master_announcement',
                    'host': self.time_sync_node.host,
                    'port': self.time_sync_node.port,
                    'worthiness': self.clock_master_worthiness(),
                    'remote_notify': 'all'
                }
                self.notify_all(n)
                self.notify_all(self.master_announce_interval_notification)

        elif notification['subject'].startswith(
                'time_sync.master_announce_interval'):
            # The time has come to remind others of our master hood.
            if self.is_master:
                n = {
                    'subject': 'time_sync.master_announcement',
                    'host': self.time_sync_node.host,
                    'port': self.time_sync_node.port,
                    'worthiness': self.clock_master_worthiness(),
                    'remote_notify': 'all'
                }
                self.notify_all(n)
                # Set the next annouce timer.
                self.notify_all(self.master_announce_interval_notification)