tango-controls/pytango

DeviceProxy in green mode: wait for ...

woutdenolf opened this issue · 4 comments

Is there a better way of doing this without the two while loops? (Maybe something with threadpool and AsyncResult.wait?)

def wait_tango_online(uri, timeout=10, initial_state=None):
    """
    Wait until Tango device is online
    """
    error = RuntimeError(f"{uri} not online in {timeout} seconds")
    with gevent.Timeout(timeout, error):
        while True:
            try:
                dev_proxy = DeviceProxy(uri)  # raises when database is not online yet
                dev_proxy.ping()   # raises when device is not online yet
            except DevFailed as e:
                gevent.sleep(0.5)
            else:
                break
        if initial_state is not None:
            while dev_proxy.state() != initial_state:
                gevent.sleep(0.1)
        return dev_proxy

To wait for a device to be online, one trick would be to subscribe to the state attribute configuration changed event:

import gevent.event
import tango.gevent


def wait(name, timeout=None):
  evt = gevent.event.Event()
  d = tango.gevent.DeviceProxy(name)
  sid = d.subscribe_event("state", tango.EventType.ATTR_CONF_EVENT,
                          lambda e: not e.err and evt.set(), [], True)
  try:
    return evt.wait(timeout)
  finally:
    d.unsubscribe_event(sid)


r = wait('a/b/c', 10)
print('Alive!' if r else 'Timed out!')

So this would get rid of your first while loop.

If you are sure your device state attribute fires events you can catch two birds with one stone
by comparing the state event value with the one you are interested:

import gevent.event
import tango.gevent

def wait_state(name, state=None, timeout=None):
  evt = gevent.event.Event()
  d = tango.gevent.DeviceProxy(name)
  def cb(e):
    if not e.err and state in {None, e.attr_value.value}:
      evt.set()

  sid = d.subscribe_event("state", tango.EventType.CHANGE_EVENT, cb, [], True)
  try:
    return evt.wait(timeout)
  finally:
    d.unsubscribe_event(sid)

r = wait_state('a/b/c', timeout=10)
print('Alive!' if r else 'Timed out!')

I had the information from @bourtemb that the ADMIN device is always instantiated last - so, we should also ping or do the state query on this one in case a server has multiple devices and we want to know when they are all "ready"/"online".

This is the case for Lima servers, for example.

@woutdenolf Can we close this ticket?