Skip to main content

Simple ZeroMQ RPC in Python

Project description

Overview

Swift RPC (szrpc) is a framework for creating remote python servers and and clients able to connect to them. It uses ZeroMQ for socket communications, and MessagePack for serialization. The key features which distinguish it from other existing solutions are:

  • Simple and clean API for creating clients, servers

  • Servers can support one or more workers running on the same host or many distinct hosts, with transparent load balancing

  • Supports multiple replies per request. Can be used to report progress for long running tasks or simply to send replies in chunks if the application needs it.

  • Reply objects can be transparently integrated into Gtk or Qt graphical frameworks through signals.

Getting Started

Installing inside a virtual environment as follows

$ python -m venv myproject
$ source myproject/bin/activate
(myproject) $ pip install szrpc

If you plan to use the server dashboard, then install the dash extras by replacing the last command with:

(myproject) $ pip install szrpc[dash]

Write your first RPC Service

The following example illustrates how simple it is to create one.

from szrpc.server import Service

class MyService(Service):
    def remote__hello_world(self, request, name=None):
        """
        Single reply after a long duration
        """
        request.reply(f'Please wait, {name} ...')
        time.sleep(10)
        return f'Hello, {name}. How is your world today?'

    def remote__date(self, request):
        """
        Single reply after a short duration
        """
        time.sleep(0.1)
        return f"Today's date is {datetime.now()}"

    def remote__progress(self, request):
        """
        Multiple replies to show progress
        """
        for i in range(10):
            time.sleep(0.1)
            request.reply(f'{i*10}% complete')
        return f"Progress done"

The above example demonstrates the following key points applicable to Services:

  • Sevices must be sub-classes of szrpc.server.Service.

  • All methods prefixed with a remote__ will be exposed remotely.

  • the very first argument to all remote methods is a request instance which contains all the information about the request.

  • The remaining arguments where present, must be keyword arguments. Positional arguments other than the initial request are not permitted.

  • Remote methods may block.

  • Multiple replies can be send back before the method completes. The return value will be the final reply sent to the client.

Running a Server instance

Once a service is defined, it can easily be used to start a server which can listen for incoming connections from multiple clients as follows:

from szrpc.server import Server

if __name__ == '__main__':
   service = MyService()
   server = Server(service=service, ports=(9990, 9991))
   server.run()

This says that our server will be available at the TCP address ‘tcp://localhost:9990’ for clients, and at the address ‘tcp://localhost:9991’ for workers. For simple cases, you don’t need to worry about workers but by default, one worker created behind the scenes to provide the service, thus it is mandatory to specify both ports. Additionally, you can change your mind and run additional workers at any point in the future on any host after the server is started.

To start the server with more than one worker on the local host, modify the instances keyword argument as follows:

server = Server(service_factory=factory, ports=(9990, 9991), instances=1)

It is possible to start the server with instances = 0 however, it will obviously not be able to handle any requests until at least one worker is started.

Server Dashboard

Swift RPC provides a web-based introspection capability that allows administrators to see active and historical calls, error messages, and basic statistics about the server.

To enable introspection, make sure the [dash] extras are installed (pip install szrpc[dash]), then provide a monitor_port when creating the server:

server = Server(service_factory=factory, ports=(9990, 9991), monitor_port=8080)
server.run()

Once the server is running, you can access the introspection dashboard by navigating to http://localhost:8080 in your web browser. The dashboard provides:

  • Uptime: How long the server has been running.

  • Total Requests: Total number of requests processed.

  • Errors: Number of failed requests.

  • Active Workers: Number of currently connected workers.

  • Active Calls: List of requests currently being processed.

  • Historical Calls: List of recently completed requests with their call arguments, results or error messages.

Starting External Workers

Starting external workers is very similar to starting Servers.

from szrpc import log
from szrpc.server import Server, Service, WorkerManager

from test_server import MyService

if __name__ == '__main__':

    service = MyService()
    log.log_to_console()
    server = WorkerManager(
        service=service, backend="tcp://localhost:9991",
        instances=2
    )
    server.run()

In the above example, we are staring two instances of workers on this host which are connected to the backend address of the main server.

Creating Clients

Clients are just as easy, if not easier to create. Here is a test client for the above service.

import time
from szrpc import log
from szrpc.client import Client

# Define response handlers
def on_done(res, data):
    print(f"Done: {res} {data!r}")

def on_err(res, data):
    print(f"Failed: {res} : {data!r}")

def on_update(res, data):
    print(f"Update: {res} {data!r}")

if __name__ == '__main__':
    log.log_to_console()
    client = Client('tcp://localhost:9990')

    # wait for client to be ready before sending commands
    while not client.is_ready():
        time.sleep(.001)

    res = client.hello_world(name='Joe')
    res.connect('done', on_done)
    res.connect('update', on_update)
    res.connect('failed', on_err)

Here we have defined a few handler functions to get called once the replies are received. A few things are noteworthy in the above client code:

  • The client automatically figures out from the server, which methods to generate. For this reason, you will get “InvalidAttribute” errors if the initial handshake has not completed before method calls are made. For most production situations, this is not a problem but in the example above, we wait until the client.is_ready() returns True before proceeding.

  • The method names at the client end do not nave the remote__ prefix. This means, overriding remote methods in the client will clobber the name.

  • Only key-worded arguments are allowed for remote methods.

  • Results are delivered asynchronously. To write synchronous code, you can call the res.wait() method on Result objects.

There are three signal types corresponding to the three types of replies a server can send:

‘done’

the server has completed processing the request, no further replies should be expected for this request

‘update’

partial data is has been received for the request. More replies should be expected.

‘failed’

The request has failed. No more replies should be expected.

Handler functions take two arguments, the first is always the result object, which is an instance of szrpc.result.Result, and the second is the decoded message from the server.

Result Classes

All results are instances of szrpc.result.Result or sub-classes thereof. The types of result objects produced can be changed to allow better integration with various frameworks. Presently, alternatives are available Gtk, Qt as well as a pure Python-based class. The pure Python result class is the default but it can easily be changed as follows.

from szrpc.result.gresult import GResult
import szrpc.client

szrpc.client.use(GResult)

my_client = szrpc.client.Client('tcp://localhost:9990')

All subsequent result objects will be proper GObjects usable with the Gtk Main loop.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

szrpc-2026.2.6.tar.gz (28.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

szrpc-2026.2.6-py3-none-any.whl (27.6 kB view details)

Uploaded Python 3

File details

Details for the file szrpc-2026.2.6.tar.gz.

File metadata

  • Download URL: szrpc-2026.2.6.tar.gz
  • Upload date:
  • Size: 28.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.1 CPython/3.13.11 Linux/6.18.6-200.fc43.x86_64

File hashes

Hashes for szrpc-2026.2.6.tar.gz
Algorithm Hash digest
SHA256 e55f8df0e4435628d295338a5905f5de8025fbf1654813d75895a5c6ca5fcedc
MD5 a105bca57c2866763ff5af8676d2443a
BLAKE2b-256 7eecae46bfb417755cf4c67dc054c3fbb0daf0dbb86890c5413d35186d143b3c

See more details on using hashes here.

File details

Details for the file szrpc-2026.2.6-py3-none-any.whl.

File metadata

  • Download URL: szrpc-2026.2.6-py3-none-any.whl
  • Upload date:
  • Size: 27.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.1 CPython/3.13.11 Linux/6.18.6-200.fc43.x86_64

File hashes

Hashes for szrpc-2026.2.6-py3-none-any.whl
Algorithm Hash digest
SHA256 68b5c959de44924d18ae6366e7b2524088294ef21ce0bedf4641505ee98a8458
MD5 abdee3456f8a982c77bb97f6e4fe31ac
BLAKE2b-256 1d8f5afd93ff91def6e127647ada277f914c8019d1a9d9ccb5181a36964361ab

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page