Skip to main content

Edge computing framework developed and maintained by the Edge Computing Research Group at Queen's University

Project description

Axon

Axon is a general-purpose RPC-proxy framework developed to facilitate machine learning research at Queen’s University in Kingston, Ontario. It focusses on fast development, being easy-to-use, and it does its best to stay out of the programmer’s way. One of Axon's goals is to make programming distributed systems as similar as possible to programming code that only runs locally. Axon does this by creating distributed equivalents of familiar concepts, such as functions and classes.

Installation

pip install axon-ECRG

QuickStart

Worker

Expose a function to distributed access with the rpc decorator:

from axon import worker

@worker.rpc()
def hello_world():
	print("hello")
	return "world"

worker.init()

Client

RPCs can be called with RemoteWorker objects:

from axon import client

hw_worker = client.get_RemoteWorker('localhost')

result = hw_worker.rpcs.hello_world().join()

print(result)

Replace 'localhost' with the IP address of the remote host, and you can call functions on other computers on your network.

Asyncio

Axon RPC requests return an AsyncResultHandle that allows for concurrent code execution during a request and parallel execution of requests. The result of the RPC invocation is obtained by calling .join() on the handle, for example:

from axon import client

hw_worker = client.get_RemoteWorker('localhost')

result = hw_worker.rpcs.hello_world()

print("Hi there!")

print(result.join())

The AsyncResultHandle class can also be awaited using asyncio! Import asyncio and run axon requests inside coroutines using async/await syntax:

from axon import client
import asyncio

async def main():
	hw_worker = client.get_RemoteWorker('localhost')
	result = await hw_worker.rpcs.hello_world()
	print(result)

asyncio.run(main())

Synchronous Stubs

If concurrency is not necessary, you may also request axon RPCs synchronously by passing in a different stub type:

import axon

hw_worker = axon.client.get_RemoteWorker('localhost', stub_type=axon.stubs.SyncStub)

result = hw_worker.rpcs.hello_world()

print(result)

Services

With axon you can expose instances of classes, not just functions, to remote access. Use register_ServiceNode to serve object instances:

from axon import worker

class TestClass():

	def print_msg(self, msg):
		print(msg)

worker.register_ServiceNode(TestClass(), 'test_service')
worker.init()

And then call services with:

from axon import client

stub = client.get_ServiceStub('localhost', endpoint_prefix='test_service')

stub.print_msg('hello!').join()

RPCs are also just a service:

from axon import client

stub = client.get_ServiceStub('localhost', endpoint_prefix='rpc')

print(stub.hello_world().join())

The same configuration options like stub_type can be used in get_ServiceStub. Services can be connected with a RemoteWorker object just like RPCs, though they're on an attribute matching the string passed to the register_ServiceNode call on worker:

from axon import client

hw_worker = client.get_RemoteWorker('localhost')

result = hw_worker.test_service.print_msg().join()

Error Propegation

Errors in the worker propagate back to the client that invoke the error, and are thrown at the line making the RPC call. For example, a worker that throws:

from axon import worker

@worker.rpc()
def raise_error():
	raise BaseException('your code sucks!!!')

worker.init()

Would result in the following error message in client:

the following error occured in worker:
Traceback (most recent call last):
  File "/home/axon/worker.py", line 77, in invoke_RPC
    result = target_fn(*args, **kwargs)
  File "<stdin>", line 2, in raise_error
BaseException: your code sucks!!!

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/axon/transport_client.py", line 40, in join
    self.value = self.future.result()
  File "/home/python3.8/concurrent/futures/_base.py", line 439, in result
    return self.__get_result()
  File "/home/python3.8/concurrent/futures/_base.py", line 388, in __get_result
    raise self._exception
  File "/home/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/axon/transport_client.py", line 74, in call_rpc_helper
    return error_handler(return_obj)
  File "/home/axon/transport_client.py", line 20, in error_handler
    raise(error)
BaseException: your code sucks!!!

If your worker is at a public IP, be careful sending error traces back to remote users. These error traces can reveal important information about your system, like the name of your home folder and details about the structure of the service. Errors should be caught and only sterile errors without any private information should be sent back to client.

Worker Discovery

It can be a logistical challenge to keep track of the IP addresses of the workers on your network. Fortunetely this problem can be solved with a simple service, the SignUpService:

from axon import worker

class SignUpService():
    def __init__(self):
            self.ips = []

    def sign_in(self, ip):
            self.ips.append(ip)

    def sign_out(self, ip):
            self.ips.remove(ip)

    def get_ips(self):
            return self.ips

s = SignUpService()
worker.register_ServiceNode(s, 'SignUpService')
worker.init()

The idea is that the SignUpService runs at a known IP address, say '192.168.2.10', that way workers are aware of. Then each worker will sign in on startup so that clients can get their IP addresses.

import axon

s = axon.client.get_ServiceStub('192.168.2.19', endpoint_prefix='SignUpService')
self_ip = axon.utils.get_self_ip()
s.sign_in(self_ip).join()

@axon.worker.rpc()
def print_msg(msg):
	print(msg)

axon.worker.init()

This has the advantage that both workers and clients only need to know one IP address, yet can discover eachother's IPs and communicate. Clients can obtain the IP addresses of all workers that have signed in:

import axon

s = axon.client.get_ServiceStub('192.168.2.19', endpoint_prefix='SignUpService')

worker_ips = s.get_ips().join()

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

axon-ECRG-0.2.0.tar.gz (13.1 kB view hashes)

Uploaded Source

Built Distribution

axon_ECRG-0.2.0-py3-none-any.whl (13.5 kB view hashes)

Uploaded Python 3

Supported by

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