General question on Component programming practice

Dear all!

First, I am rather new to autobahn/crossbar, so when I missed a link or description I appreciate your forbearance. :slight_smile:

I have a scientific instrument which exposes a Python API for handling commands, parameter setting/retrival, events and the like.

I want to control this machine from another computer. While searching on how to accomplish this I came across autobahn and crossbar.io.
For using these I understood, that I can run a crossbar router on the/a (remote) computer and on the instrument’s PC prepare autobahn scripts that register procedures (and event handling) at the router and once they are running are listening and answering.

The controlling instance also communicates with the router via autobahn scripts to reach the instrument’s PC by RPC. So far so good.

In the examples I have seen so far, the control script instantiates a component class, runs it to accomplish the specific task and then leaves the session again. In my understanding running the same task again, will require the same “overhead” as in the first run.

That’s now my question. Is this the way to go when using autobahn? Or are there other practices which e.g. keep the session alive and just trigger a registered procedure, say by some callback, which than presumably would save some time/resources?

Thanks a lot in advance for your replies and best wishes
Markus

I think you almost got it;)

in your scenario, the measurement instrument should be wrapped by the Autobahn based client component, and thought of as just another microservice in the realm (the client joins on the router it connects to).

A Web UI (eg using AutobahnJS) on the same realm is another microservice - simply one where a human happens to sit in front (and produces/consumes “I/O” … keyboard, mouse, monitor).

Your client, wrapping your instrument, runs all the time. It does not exit. It will usually register procedures to expose its functionality (eg “start-measurement” or “get-settings”), as well as publish event (eg “on-measurement-started”).

It might also call into procedures registered by other microservices in the realm (eg “get-weather-forecast”)

Assuming you know how to talk to your measurement device from Python, there are 2 main things to crack:

  1. come up with a WAMP API for your measurement instrument and use case. only you can do it, it’s an art (there is no right and wrong), and it has major consequences (the APIs in your realm structure your whole system, and define how microservices can even talk to each other … what procedures, what events)
  2. if talking to your measurement instrument involves blocking Python code, this must be handled appropriately without blocking the reactor/event loop on the main thread (the one with the outgoing network connection to your router)

Hope that helps … I would stress: APIs first, and proper domain level and use case modeling for that are critical. The blocking thing is just a “technical annoyance” (a pure engineering task).

Cheers,
/Tobias

Hi Tobias,

the part from in your scenario until "get-weather-forecast") it was/is clear to me, especially that the client, wrapping my instrument, will not exit.

I am wondering, how the other client is set up. This very (autobahn) client will be part of a plugin for an existing acquisition software. When this client does a remote procedure call, shall it exit after fulfilling its task, i.e. the “Component”-instance get’s destroyed, or is there some coding practice to keep it alive to safe some overhead, or perhaps there are some mechanisms under the autobahn-hood, that deals with it?
The set of RPCs is limited, about 20 different, further functionality is achieved via the call’s arguments.

Best wishes
Markus

connection_schema

ahh, ok!

shall it exit after fulfilling its task

in general, WAMP session are long-lived (are designed for that), and the overhead is pretty much irrelevant here. I have tested 180k (mostly idle) sessions on my notebook years ago;) np.

I would keep all session (both the acquisition SW and the instrument) alive all the time. Even use websocket ping/pong (enable heartbeating from crossbar). and activate auto-reconnect. IOW: don’t worry, “always on” is just fine.

Thanks a lot!

Can you direct me to examples that deal with automatic reconnect and multiple RPCs within a session?

Best wishes
Markus

actually, all you need for a start should be

runner = ApplicationRunner(url=url, realm=realm, extra=extra)
runner.run(ClientSession, auto_reconnect=True)

for the client side auto-reconnect, and

“auto_*” ping options in the default config


note that activating client initiated (rather than router initiated heartbeats … what above does) currently cannot be easily activated via ApplicationRunner (the underlying classes of that support it) … as long as your connections don’t run over WAN, that wouldn’t mapper anyways. sorry, I’m a bit under time pressure right now … just wanted to give some hints

Hi Tobias!

It works, client 1 via router asks client 2 for Instrument data, client 2 asks instrument and the answer eventually gets back to client 1. Very nice! :slight_smile:

I am almost there, :wink: where I want to be.

My programming experience regarding co-routines is rather small. Therefore I have the newbie problem, that once the runner.run() commands runs for the remote client, I have no clue on how to call the procedures registered during onJoin. That is, what I want to do from within the plugin.

I have seen, that I can run with start_loop=False but how to use the return value?

Thanks a lot for your patience!
Markus

p.s.:
auto-reconnect is not know to run(), probably because I am using asyncio?

1 Like

great! progress=)

rgd “asynchronous programming” in python, either using twisted or asyncio: that’s a broad topic of course.

since we have so many code examples (even though the docs lack), practically, I would piece together what you need from those examples, plus of course read a bit about asynchronous python in parallel on the go as you need

besides the examples in crossbar-examples repo, and rgd your specific question of how to do multiple calls in onJoin

you can do the same in asyncio rather than twisted:

then, besides choice of networking stack (twisted vs asyncio), autobahn also has 2 abstractions: the one is using ApplicationSession and you override methods to react to stuff. there also is a (more functional, modern) approach using observers and listeners. anyways, we have too many options;)

and here is the example in “asyncio + observer” flavor: https://github.com/crossbario/autobahn-python/blob/master/examples/asyncio/wamp/component/frontend.py

sidenote: the example seems to be very old … it uses “yield from” which was necessary on python 3.3/3.4 … nowerdays “await” should be used. sorry, Python async has some history …