tango-controls / pytango

This project was moved to gitlab.com
http://pytango.rtfd.io
55 stars 44 forks source link

DeviceProxy in green mode: wait for ... #366

Closed woutdenolf closed 4 years ago

woutdenolf commented 4 years ago

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
tiagocoutinho commented 4 years ago

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.

tiagocoutinho commented 4 years ago

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!')
mguijarr commented 4 years ago

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.

ajoubertza commented 4 years ago

@woutdenolf Can we close this ticket?