Dynamically assign function in Ray Actor

How severe does this issue affect your experience of using Ray?

  • Medium: It contributes to significant difficulty to complete my task, but I can work around it.

I am trying to initialize a ray.remote class with a function, as opposed to simply defining it as a method in the class. I have only been able to do this by creating a proxy function in the class which then invokes this function. My guess is that this has something to do with how Ray is hanfing distributing the code, but I’d like to get a better understanding of this limitation.

Code example

from typing import Any
import ray 
import traceback
import time 

@ray.remote
class ActorProxyFunc():
    
    def __init__(self, func):
        self.func = func
        self.func_no_proxy = func
        
    def func(self):
        print("called func")
        self.func()

def hello():
    print("hello dynamic")

if __name__ == '__main__':

    a = ActorProxyFunc.remote(hello)
    
    print("Calling the hello function through the func() proxy")
    try:
        ref = a.func.remote()
        ray.get(ref)
    except:
        print(traceback.format_exc())
    
    # This just used so logs are better ordered
    time.sleep(1)
    
    print("Trying to call the hello function directly")
    try:
        ref = a.func_no_proxy.remote()
        ray.get(ref)
    except:
        print(traceback.format_exc())
    finally:
        # Trying to stop ray from blowing up and hanging my terminal session
        del a

@Patrick_S Good question. When actors are created, the driver or script invoking a=ActorProxyFunc.remote(hello) registers the pickled Actor with the GCS, which then
initiates a actor-creation request after talking to a Raylet to determine on what node
this Actor can be scheduled base on its resources. At this point the code is already picked, with
all its methods. Dynamically adding code would require updating the pickled code with the new method.

cc: @Ruiyang_Wang do you know if that’s possible to dynamically create actor methods?

There are 2 methods called, beside what Ray does, with this statement, a=ActorProxyFunc.remote(hello), new and init. Since my code is only adding the method during init that implies that the object is pickled and registered before init. In the code below, I take a different approach and add the method during new(). If you comment out the whole RayTestDynamicMethod class you will see it runs as expected. If you then comment out everything but that class, you get this error:

TypeError: RayTestDynamicMethod.__new__() missing 1 required positional argument: 'funk'

which implies that the ray decorator does not pass any arguments into new so it fails when parsing or compiling.

import ray

## Run 1 comment out this class
@ray.remote
class RayTestDynamicMethod():
    
    def __new__(cls, funk):
        print("Creating a new Person object")
        instance = super().__new__(cls)
        setattr(instance, funk.__name__, funk)
        return instance

## Run 2, Comment out everything below here
class TestDynamicMethod():
    
    def __new__(cls, funk):
        print("Creating a new Person object")
        instance = super().__new__(cls)
        setattr(instance, funk.__name__, funk)
        return instance
    
def hello():
    print("hello")
    
if __name__ == '__main__':
    tda = TestDynamicMethod(hello)
    tda.hello()