asynchronous execution

Daffi utilizes classes known as execution modifiers to transmit requests to a remote process. These modifiers define the manner in which requests should be executed and how the system should await the resulting computation. The default modifier, which we have implicitly used in previous examples, is FG, which stands for "foreground." This modifier blocks the main process until the computed result is returned.

In the following example, we will use the BG execution modifier, which is short for "background." This modifier returns an instance of AsyncResult rather than the result itself, making it appropriate for long-running tasks or tasks in which the result is not critical.

calculator_service.py content:

import logging
from daffi import Global
from daffi.registry import Callback

logging.basicConfig(level=logging.INFO)


class CalculatorService(Callback):
    auto_init = True

    def calculate_fibonacci(self, n):
        # Check if n is 0
        # then it will return 0
        if n == 0:
            return 0

        # Check if n is 1,2
        # it will return 1
        elif n == 1 or n == 2:
            return 1

        else:
            return self.calculate_fibonacci(n - 1) + self.calculate_fibonacci(n - 2)


if __name__ == '__main__':
    Global(init_controller=True, host="localhost", port=8888).join()

calculator_client.py content:

import time
import logging
from daffi import Global, BG, FG
from daffi.registry import Fetcher

logging.basicConfig(level=logging.INFO)


class CalculatorClient(Fetcher):

    # Execution modifier are shared across all fetcher's methods
    exec_modifier = BG(timeout=30)

    def calculate_fibonacci(self, n):
        """Proxy fetcher"""
        pass


if __name__ == '__main__':
    g = Global(host="localhost", port=8888)

    calc_client = CalculatorClient()
    feature = calc_client.calculate_fibonacci(20)

    print("Waiting")
    time.sleep(10)

    result = feature.get()
    print(f"Fibonacci result: {result}")

    # Execution modifier can be specified at execution time
    result = calc_client.calculate_fibonacci.call(exec_modifier=FG, n=15)
    print(f"Fibonacci result: {result}")

    g.stop()

Execute in two separate terminals:

python3 calculator_service.py
python3 calculator_client.py

calculator_service.py content:

import logging
from daffi import Global
from daffi.decorators import callback

logging.basicConfig(level=logging.INFO)


@callback
def calculate_fibonacci(n):
    # Check if n is 0
    # then it will return 0
    if n == 0:
        return 0

    # Check if n is 1,2
    # it will return 1
    elif n == 1 or n == 2:
        return 1

    else:
        return calculate_fibonacci(n - 1) + calculate_fibonacci(n - 2)


if __name__ == '__main__':
    Global(init_controller=True, host="localhost", port=8888).join()

calculator_client.py content:

import time
import logging
from daffi import Global, BG, FG
from daffi.decorators import fetcher

logging.basicConfig(level=logging.INFO)


@fetcher(exec_modifier=BG(timeout=30))
def calculate_fibonacci(n):
    """Proxy fetcher"""
    pass


if __name__ == '__main__':
    g = Global(host="localhost", port=8888)

    feature = calculate_fibonacci(20)

    print("Waiting")
    time.sleep(10)

    result = feature.get()
    print(f"Fibonacci result: {result}")

    # Execution modifier can be specified at execution time
    result = calculate_fibonacci.call(exec_modifier=FG, n=15)
    print(f"Fibonacci result: {result}")

    g.stop()

Execute in two separate terminals:

python3 calculator_service.py
python3 calculator_client.py

Note

To use UNIX socket instead of TCP for communication, you should remove the host and port parameters from the initialization of the Global object, and optionally include the unix_sock_path parameter.