To perform remote procedure calls you just need to connect two peers, and then, on your local peer instance, call a registered function with the right parameters. You will then receive the return value of the remotely executed function.
# server.py import string import pseud from pseud.utils import register_rpc server = pseud.Server('remote') server.bind('tcp://127.0.0.1:5555') # register locally for this server only server.register_rpc(string.lower) # register globally for all rpc instances register_rpc(string.upper) await server.start()
# client.py import pseud client = pseud.Client('remote') client.connect('tcp://127.0.0.1:5555') res1 = await client.lower('ABC') res2 = await client.upper('def') assert res1 == 'abc' assert res2 == 'DEF'
Registration is a necessary step to control what callable you want to expose for remote peers.
The register_rpc decorator from :mod:`pseud.utils` module must be used to register a callable for all workers of the current process.
from pseud.utils import regsiter_rpc @register_rpc def call_me(): return 'Done'
An RPC instance exposes its own register_rpc function, which is used to register a callable only for that same RPC instance.
def call_me(): return 'Done' server.register_rpc(call_me)
You can also instantiate a registry and give it to :mod:`pseud.utils.register_rpc`, and pass it as an init parameter in the RPC. It is more convenient to use register_rpc as a decorator
import pseud from pseud.utils import register_rpc, create_local_registry registry = create_local_registry('worker') @register_rpc(registry=registry) def call_me(): return 'Done' server = pseud.Server('worker', registry=registry)
Name it !
You can also decide to provide your own name (dotted name) to the callable
from pseud.utils import regsiter_rpc @register_rpc('this.is.a.name') def call_me(): return 'Done'
client.this.is.a.name().get() == 'Done'
Server wants to make the client do work
In order to let the server send jobs to its connected clients, the caller
should know the identity of the specified client beforehand.
By default all clients are anonymous for the server. This is why it
is necessary to rely on your own
security_plugin to perform
The most simple authentication that you can use is
plain for the client,
password arguments to the constructor.
Then on the server side
trusted_peer will just trust that given
will identify the peer, and ignore the password.
Given a client whose identity is
'client1', with a registered function named
addition, the following statement may be used to send work from the server
to the client:
# server.py server = Server('service', security_plugin='trusted_peer') server.bind('tcp://127.0.0.1:5555') await server.start()
# client.py client = Client('service', security_plugin='plain', user_id='client1', password='') client.connect('tcp://127.0.0.1:5555') @client.register_rpc def addition(a, b): return a + b await client.hello('Me') # perform a first call to register itself
The client needs to perform at least one call to the server to register itself. Otherwise the server won't know a client is connected to it. On real condition the heartbeat backend will take care of it. So you do not have to worry about it.
# server.py result = await server.send_to('client1').addition(2, 4) assert result == 6
client1 string is the user_id provided by the client.