From 8022b48c2b4ada65b79cc8c4cd6adfb134967760 Mon Sep 17 00:00:00 2001 From: "albert.zah" Date: Tue, 9 Jan 2024 11:58:55 +0000 Subject: [PATCH 1/6] docs: add api doc. --- docs/source/api.rst | 21 ++++++++++--- docs/source/usage.rst | 4 +-- fed/api.py | 68 +++++++++++++++++++++++++++++++++++++++++++ fed/config.py | 7 +++-- 4 files changed, 91 insertions(+), 9 deletions(-) diff --git a/docs/source/api.rst b/docs/source/api.rst index 58411322..fc50135e 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -1,7 +1,20 @@ API -=== +=========== -.. autosummary:: - :toctree: generated +fed.api module +-------------- - RayFed +.. automodule:: fed + :members: init, remote, get, shutdown, kill + +fed.config module +----------------- + +.. automodule:: fed.config + :members: ClusterConfig, CrossSiloMessageConfig, GrpcCrossSiloMessageConfig + +.. Module contents +.. --------------- + +.. .. automodule:: fed +.. :members: diff --git a/docs/source/usage.rst b/docs/source/usage.rst index c76bc51f..303fcfc0 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -15,9 +15,7 @@ To use RayFed, first install it using pip: Starting RayFed --------------- -To start a RayFed application, you can use ``fed.init()`` function: - -.. autofunction:: fed.init +To start a RayFed application, you can use ``fed.init`` function: For example: diff --git a/fed/api.py b/fed/api.py index 96fc47a6..15fd3a92 100644 --- a/fed/api.py +++ b/fed/api.py @@ -84,6 +84,7 @@ def init( addresses: optional; a dict describes the addresses configurations. E.g. .. code:: python + { # The address that can be connected to `alice` by other parties. 'alice': '127.0.0.1:10001', @@ -111,6 +112,7 @@ def init( Example: .. code:: python + { "cross_silo_comm": { "messages_max_size_in_bytes": 500*1024, @@ -125,6 +127,7 @@ def init( For alice, .. code:: python + { "ca_cert": "root ca cert of other parties.", "cert": "alice's server cert", @@ -134,6 +137,7 @@ def init( For bob, .. code:: python + { "ca_cert": "root ca cert of other parties.", "cert": "bob's server cert", @@ -419,6 +423,63 @@ def remote(self, *cls_args, **cls_kwargs): # This is the decorator `@fed.remote` def remote(*args, **kwargs): + """Defines a remote function or an actor class. + + This function can be used as a decorator with no arguments + to define a remote function or actor as follows: + + .. testcode:: + + import fed + + @fed.remote + def f(a, b, c): + return a + b + c + + object_ref = f.part('alice').remote(1, 2, 3) + result = fed.get(object_ref) + assert result == (1 + 2 + 3) + + @fed.remote + class Foo: + def __init__(self, arg): + self.x = arg + + def method(self, a): + return self.x + a + + actor_handle = Foo.party('alice').remote(123) + object_ref = actor_handle.method.remote(321) + result = fed.get(object_ref) + assert result == (123 + 321) + + Equivalently, use a function call to create a remote function or actor. + + .. testcode:: + + def g(a, b, c): + return a + b + c + + remote_g = fed.remote(g) + object_ref = remote_g.party('alice').remote(1, 2, 3) + assert fed.get(object_ref) == (1 + 2 + 3) + + class Bar: + def __init__(self, arg): + self.x = arg + + def method(self, a): + return self.x + a + + RemoteBar = fed.remote(Bar) + actor_handle = RemoteBar.party('alice').remote(123) + object_ref = actor_handle.method.remote(321) + result = fed.get(object_ref) + assert result == (123 + 321) + + + It can also be used with specific keyword arguments just same as ray options. + """ def _make_fed_remote(function_or_class, **options): if inspect.isfunction(function_or_class) or fed_utils.is_cython( function_or_class @@ -518,6 +579,13 @@ def get( def kill(actor: FedActorHandle, *, no_restart=True): + """Kill an actor forcefully. + + Args: + actor: Handle to the actor to kill. + no_restart: Whether or not this actor should be restarted if + it's a restartable actor. + """ job_name = get_global_context().get_job_name() current_party = _get_party(job_name) if actor._node_party == current_party: diff --git a/fed/config.py b/fed/config.py index 230d9792..3aeccde6 100644 --- a/fed/config.py +++ b/fed/config.py @@ -158,6 +158,7 @@ class GrpcCrossSiloMessageConfig(CrossSiloMessageConfig): `retry-policy `_. # noqa .. code:: python + { "maxAttempts": 4, "initialBackoff": "0.1s", @@ -167,8 +168,10 @@ class GrpcCrossSiloMessageConfig(CrossSiloMessageConfig): "UNAVAILABLE" ] } - grpc_channel_options: A list of tuples to store GRPC channel options, - e.g. [ + grpc_channel_options: A list of tuples to store GRPC channel options, e.g. + .. code:: python + + [ ('grpc.enable_retries', 1), ('grpc.max_send_message_length', 50 * 1024 * 1024) ] From 01df7ca34897afac421e1a56e40624530e2101d9 Mon Sep 17 00:00:00 2001 From: "albert.zah" Date: Tue, 9 Jan 2024 12:07:21 +0000 Subject: [PATCH 2/6] Use pydata_sphinx_theme. --- docs/doc-requirements.txt | 2 +- docs/source/conf.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/doc-requirements.txt b/docs/doc-requirements.txt index 89138c8b..71dc8e93 100644 --- a/docs/doc-requirements.txt +++ b/docs/doc-requirements.txt @@ -5,4 +5,4 @@ protobuf>=3.9.2,<3.20 # The following dependencies are required for doc-building only. jinja2<3.1.0 -sphinx_rtd_theme +pydata_sphinx_theme diff --git a/docs/source/conf.py b/docs/source/conf.py index 6939e8fb..75bcc8d5 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -29,7 +29,7 @@ # -- Options for HTML output -html_theme = 'sphinx_rtd_theme' +html_theme = 'pydata_sphinx_theme' # -- Options for EPUB output epub_show_urls = 'footnote' From c3478718f9555066afaaf6ab0b49222a1f77b0c8 Mon Sep 17 00:00:00 2001 From: "albert.zah" Date: Tue, 9 Jan 2024 12:20:54 +0000 Subject: [PATCH 3/6] Fix init docstring. --- docs/source/usage.rst | 2 +- fed/api.py | 35 +++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/docs/source/usage.rst b/docs/source/usage.rst index 303fcfc0..95d8546f 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -15,7 +15,7 @@ To use RayFed, first install it using pip: Starting RayFed --------------- -To start a RayFed application, you can use ``fed.init`` function: +To start a RayFed application, you can use :py:meth:`fed.init` function: For example: diff --git a/fed/api.py b/fed/api.py index 15fd3a92..2a13451a 100644 --- a/fed/api.py +++ b/fed/api.py @@ -82,7 +82,6 @@ def init( Args: addresses: optional; a dict describes the addresses configurations. E.g. - .. code:: python { @@ -93,23 +92,27 @@ def init( # The address that can be connected to `carol` by other parties. 'carol': '127.0.0.1:10003', } + party: optional; self party. + config: optional; a dict describes general job configurations. Currently the - supported configurations are [`cross_silo_comm`, 'barrier_on_initializing']. - * `cross_silo_comm`: optional; a dict describes the cross-silo common - configs, the supported configs can be referred to - `fed.config.CrossSiloMessageConfig` and - `fed.config.GrpcCrossSiloMessageConfig`. Note that, the - `cross_silo_comm.messages_max_size_in_bytes` will be overrided - if `cross_silo_comm.grpc_channel_options` is provided and contains - `grpc.max_send_message_length` or `grpc.max_receive_message_length`. - * `barrier_on_initializing`: optional; a bool value indicates whether to - wait for all parties to be ready before starting the job. If set - to True, the job will be started after all parties are ready, - otherwise, the job will be started immediately after the current - party is ready. - - Example: + supported configurations are ['cross_silo_comm', 'barrier_on_initializing']. + cross_silo_comm + optional; a dict describes the cross-silo common + configs, the supported configs can be referred to + :py:meth:`fed.config.CrossSiloMessageConfig` and + :py:meth:`fed.config.GrpcCrossSiloMessageConfig`. Note that, the + `cross_silo_comm.messages_max_size_in_bytes` will be overrided + if `cross_silo_comm.grpc_channel_options` is provided and contains + `grpc.max_send_message_length` or `grpc.max_receive_message_length`. + barrier_on_initializing + optional; a bool value indicates whether to + wait for all parties to be ready before starting the job. If set + to True, the job will be started after all parties are ready, + otherwise, the job will be started immediately after the current + party is ready. + + E.g. .. code:: python From 9e4ea6e258a19e18316dfcbd6a5a75ff6dfd1b4d Mon Sep 17 00:00:00 2001 From: "albert.zah" Date: Tue, 9 Jan 2024 12:35:58 +0000 Subject: [PATCH 4/6] Fix docstrings of api. --- docs/source/conf.py | 2 ++ fed/api.py | 28 ++++++++++++++---------- fed/config.py | 53 ++++++++++++++++++++++++++------------------- 3 files changed, 49 insertions(+), 34 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 75bcc8d5..219db02f 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -17,6 +17,8 @@ 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.intersphinx', + 'sphinx.ext.viewcode', + 'sphinx.ext.extlinks', ] intersphinx_mapping = { diff --git a/fed/api.py b/fed/api.py index 2a13451a..ebb1e4a9 100644 --- a/fed/api.py +++ b/fed/api.py @@ -81,7 +81,8 @@ def init( Initialize a RayFed client. Args: - addresses: optional; a dict describes the addresses configurations. E.g. + addresses: + optional; a dict describes the addresses configurations. E.g. .. code:: python { @@ -92,10 +93,10 @@ def init( # The address that can be connected to `carol` by other parties. 'carol': '127.0.0.1:10003', } - - party: optional; self party. - - config: optional; a dict describes general job configurations. Currently the + party: + optional; self party. + config: + optional; a dict describes general job configurations. Currently the supported configurations are ['cross_silo_comm', 'barrier_on_initializing']. cross_silo_comm optional; a dict describes the cross-silo common @@ -126,7 +127,8 @@ def init( }, "barrier_on_initializing": True, } - tls_config: optional; a dict describes the tls config. E.g. + tls_config: + optional; a dict describes the tls config. E.g. For alice, .. code:: python @@ -146,17 +148,19 @@ def init( "cert": "bob's server cert", "key": "bob's server cert key", } - logging_level: optional; the logging level, could be `debug`, `info`, - `warning`, `error`, `critical`, not case sensititive. - job_name: optional; the job name of the current job. Note that, the job name + logging_level: + optional; the logging level, could be `debug`, `info`, `warning`, `error`, + `critical`, not case sensititive. + job_name: + optional; the job name of the current job. Note that, the job name must be identical in all parties, otherwise, messages will be ignored because of the job name mismatch. If the job name is not provided, an default fixed name will be assigned, therefore messages of all anonymous jobs will be mixed together, which should only be used in the single job scenario or test mode. - sending_failure_handler: optional; a callback which will be triggeed if - cross-silo message sending failed and exit_on_sending_failure in config is - True. + sending_failure_handler: + optional; a callback which will be triggeed if cross-silo message sending + failed and exit_on_sending_failure in config is True. Examples: >>> import fed >>> import ray diff --git a/fed/config.py b/fed/config.py index 3aeccde6..e344dd3d 100644 --- a/fed/config.py +++ b/fed/config.py @@ -77,36 +77,45 @@ def get_job_config(job_name: str = None) -> JobConfig: @dataclass class CrossSiloMessageConfig: - """A class to store parameters used for Proxy Actor + """A class to store parameters used for Proxy Actor. Attributes: - proxy_max_restarts: The max restart times for the send proxy. - serializing_allowed_list: The package or class list allowed for + proxy_max_restarts: + The max restart times for the send proxy. + serializing_allowed_list: + The package or class list allowed for serializing(deserializating) cross silos. It's used for avoiding pickle - deserializing execution attack when crossing solis. - send_resource_label: Customized resource label, the SenderProxyActor + deserializing execution attack when crossing silos. + send_resource_label: + Customized resource label, the SenderProxyActor will be scheduled based on the declared resource label. For example, when setting to `{"my_label": 1}`, then the sender proxy actor will be - started only on Nodes with `{"resource": {"my_label": $NUM}}` where + started only on nodes with `{"resource": {"my_label": $NUM}}` where $NUM >= 1. - recv_resource_label: Customized resource label, the ReceiverProxyActor + recv_resource_label: + Customized resource label, the ReceiverProxyActor will be scheduled based on the declared resource label. For example, when setting to `{"my_label": 1}`, then the receiver proxy actor will be - started only on Nodes with `{"resource": {"my_label": $NUM}}` where + started only on nodes with `{"resource": {"my_label": $NUM}}` where $NUM >= 1. - exit_on_sending_failure: whether exit when failure on - cross-silo sending. If True, a SIGTERM will be signaled to self - if failed to sending cross-silo data. - messages_max_size_in_bytes: The maximum length in bytes of - cross-silo messages. If None, the default value of 500 MB is specified. - timeout_in_ms: The timeout in mili-seconds of a cross-silo RPC call. - It's 60000 by default. - http_header: The HTTP header, e.g. metadata in grpc, sent with the RPC request. + exit_on_sending_failure: + whether exit when failure on cross-silo sending. If True, a SIGINT will be + signaled to self if failed to sending cross-silo data and exit then. + messages_max_size_in_bytes: + The maximum length in bytes of cross-silo messages. If None, the default + value of 500 MB is specified. + timeout_in_ms: + The timeout in mili-seconds of a cross-silo RPC call. It's 60000 by + default. + http_header: + The HTTP header, e.g. metadata in grpc, sent with the RPC request. This won't override basic tcp headers, such as `user-agent`, but concat them together. - max_concurrency: the max_concurrency of the sender/receiver proxy actor. - use_global_proxy: Whether using the global proxy actor or create new proxy - actor for current job. + max_concurrency: + the max_concurrency of the sender/receiver proxy actor. + use_global_proxy: + Whether using the global proxy actor or create new proxy actor for current + job. """ proxy_max_restarts: int = None @@ -152,9 +161,9 @@ class GrpcCrossSiloMessageConfig(CrossSiloMessageConfig): """A class to store parameters used for GRPC communication Attributes: - grpc_retry_policy: a dict descibes the retry policy for - cross silo rpc call. If None, the following default retry policy - will be used. More details please refer to + grpc_retry_policy: + a dict descibes the retry policy for cross silo rpc call. If None, the + following default retry policy will be used. More details please refer to `retry-policy `_. # noqa .. code:: python From 3061d7a372969abff24e66fe7fbe1aa0e40bf0f1 Mon Sep 17 00:00:00 2001 From: "albert.zah" Date: Tue, 9 Jan 2024 12:37:58 +0000 Subject: [PATCH 5/6] Fix docstring. --- fed/api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fed/api.py b/fed/api.py index ebb1e4a9..9d7465fd 100644 --- a/fed/api.py +++ b/fed/api.py @@ -83,6 +83,7 @@ def init( Args: addresses: optional; a dict describes the addresses configurations. E.g. + .. code:: python { From db56c5a5a42e3104e4249a8f69cd4b6f0b74f5b7 Mon Sep 17 00:00:00 2001 From: "albert.zah" Date: Tue, 9 Jan 2024 12:40:54 +0000 Subject: [PATCH 6/6] Fix lint. --- fed/api.py | 1 + fed/config.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fed/api.py b/fed/api.py index 9d7465fd..a8d2cbf3 100644 --- a/fed/api.py +++ b/fed/api.py @@ -488,6 +488,7 @@ def method(self, a): It can also be used with specific keyword arguments just same as ray options. """ + def _make_fed_remote(function_or_class, **options): if inspect.isfunction(function_or_class) or fed_utils.is_cython( function_or_class diff --git a/fed/config.py b/fed/config.py index e344dd3d..a8799ee4 100644 --- a/fed/config.py +++ b/fed/config.py @@ -107,13 +107,13 @@ class CrossSiloMessageConfig: timeout_in_ms: The timeout in mili-seconds of a cross-silo RPC call. It's 60000 by default. - http_header: + http_header: The HTTP header, e.g. metadata in grpc, sent with the RPC request. This won't override basic tcp headers, such as `user-agent`, but concat them together. - max_concurrency: + max_concurrency: the max_concurrency of the sender/receiver proxy actor. - use_global_proxy: + use_global_proxy: Whether using the global proxy actor or create new proxy actor for current job. """