Worker class encapsulates the behaviors of FL participants (i.e., server and clients) and can be described via a collection of (message, handler) pairs. This tutorial focuses on helping you develop your own Worker subclasses. More details about the event-driven programming paradigm can be found in Event-driven Architecture.

Base Class of Workers

We show the class hierarchy for FS workers as below, and you can develop your own workers by inheriting the appropriate base class and making specialization.

Worker # Abstract class for both client and server
├── BaseClient # Abstract class for client
│   ├── Client # An implemented client with BaseClient
│   │   ├── XXXClient # Client for a specific algorithm with minor modifications
│   │   ├── ... ...
├── BaseServer # Abstract class for server
│   ├── Server # An implemented server with BaseServer
│   │   ├── XXXServer # Server for a specific algorithm with minor modifications
│   │   ├── ... ...

You can either develop your client (or server) from federatedscope.core.workers.base_client.BaseClient (or federatedscope.core.workers.base_server.BaseServer) for a brand new client or from federatedscope.core.workers.client.Client (or federatedscope.core.workers.server.Server) for minor modifications.

We have two mechanisms below to help you keep your Worker subclasses complete, which are all essential for the usage of Event-driven Architecture.

Completeness of implementation

In this section, we give a hands-on tutorial for developing a new client, which can be adapted to developing a new server. If you want to develop your own client with BaseClient as the base class, you must implement your own callback_funcs_for_xxx, which are abc.abstractmethod in BaseClient as shown below:

class BaseClient(Worker):
    def __init__(self, ID, state, config, model, strategy):
        super(BaseClient, self).__init__(ID, state, config, model, strategy)
        self.msg_handlers = dict()
        self.msg_handlers_str = dict()
    def register_handlers(self, msg_type, callback_func, send_msg=[None]):
        if msg_type in self.msg_handlers.keys():
            logger.warning(f"Overwriting msg_handlers {msg_type}.")
        self.msg_handlers[msg_type] = callback_func
        self.msg_handlers_str[msg_type] = (callback_func.__name__, send_msg)

    def _register_default_handlers(self):

    def run(self):
        raise NotImplementedError

    def callback_funcs_for_model_para(self, message):
        raise NotImplementedError

    def callback_funcs_for_assign_id(self, message):
        raise NotImplementedError

    def callback_funcs_for_join_in_info(self, message):
        raise NotImplementedError

    def callback_funcs_for_address(self, message):
        raise NotImplementedError

    def callback_funcs_for_evaluate(self, message):
        raise NotImplementedError

    def callback_funcs_for_finish(self, message):
        raise NotImplementedError

    def callback_funcs_for_converged(self, message):
        raise NotImplementedError

These messages and handlers are necessary for making up a complete FL course. With them properly implemented, you can run FS with your own client!

Completeness of messages and handlers

In this section, we will introduce the mechanism that would somewhat help you ensure the completeness of messages and handlers. This mechanism is to check the situation below:


If the messages and handlers are not set properly, the FL course might fail due to missing handlers for some specific message, hander never being used, etc. Thus, this mechanism will help you debug.

How to enable this check

Following our config rules, you can enable this feature by setting cfg.check_completeness=True, or running in the command line with check_completeness True:

python federatedscope/ --cfg scripts/example_configs/femnist.yaml check_completeness True

Status for the completeness check

There are three statuses for the check: Pass, WARNING, and Error.

Pass: Everything goes fine with workers.

WARNING: The FL course goes well, but some handers are never used.


Error: The FL course fails as there is no path from start (i.e., the initial state) to end (i.e., the state corresponding to the end of an FL course).

Debug information of the completeness check

With the help of the networkx, we can quickly visualize and find out whether there is a potential failure. A directed graph will be plotted and saved into cfg.exp_dir folder to remind you something might go wrong: