Giter Club home page Giter Club logo

Comments (3)

mfateev avatar mfateev commented on August 18, 2024

Thinking about it I believe we should solve this with another common requirement to support multiple implementations of the same interface for activities.

So it looks like there is a need to implement many to many relationship between interfaces and activity implementations and use only some of the interfaces for workflow->activity implementation calls.

Currently an activity interface is used to define two distinct properties of an activity. It defines a strongly typed interface for calling and implementing activities and it defines activity type name string. This string is used to convert calls on the activity stub to ScheduleActivityTask <activityName, input> decision. And then by an activity worker to locate an appropriate implementation. The implementation is found by registering it with the name of activities extracted from the interfaces the implementation implements.

As an activity interface by design defines only one activity type for each method it is not possible to have multiple implementations of this interface to share the same activity worker listening on a common task list. Also as currently there is no @ActivityInterface annotation then every interface a class implements becomes an activity interface when registered with an activity worker. This is known problem when the same mixin interface is implemented by multiple activity implementations.

Let's look at the possible solutions.

  1. Keep one interface to one activity type per method mapping, but introduce @ActivityInterface annotation to mark interfaces that are used to define activity types.
    Code example:
public interface Base {
    void foo();
}

// Defines MyActivity1_bar and MyActivity1_foo activity types
@ActivityInterface
public interface MyActivity1 extends Base {
    void bar();
}

// Defines MyActivity2_foo activity type
@ActivityInterface
public interface MyActivity2 extends Base {
}

public class MyActivityImpl1 implements MyActivity1, Runnable {
    public void foo() {
        // activity impl
    }
    
    public void bar() {
        // activity impl
    }
    
    public void run() {
        // this is not activity method as Runnable is not an activity
    }
}

public class MyActivityImpl2 implements MyActivity2 {
    public void foo() {
        // activity impl
    }
}

worker.registerActivitiesImplementations(new MyActivityImpl1(), new MyActivityImpl2());


public interface MyWorkflow {
    @WorkflowMethod
    void execute();
}

public class MyWorkflowImpl implements MyWorklfow {
    MyActivity1 a = Workflow.newActivityStub(MyActivity1.class);
    MyActivity2 b = Workflow.newActivityStub(MyActivity2.class);
    // The following is going to fail at runtime as Runnable is not annotated with @ActivityInterface
    Runnable invalid = Workflow.newActivityStub(Runnable.class); 
    // The following is going to fail at runtime as Base is not annotated with @ActivityInterface
    Base invalid2 = Workflow.newActivityStub(Base.class); 

    // This is fine as both MyActivity1 and MyActivity2 extend Base
    Base[] all = new Base[] {a, b};
    
    public void execute() {
        a.bar(); 
        for(Base b:all) {
            b.foo();
        }
    }
}

from sdk-java.

mfateev avatar mfateev commented on August 18, 2024
  1. Another option is to allow multiple implementations of an activity interface and use additional qualifier (which defaults to implementation class name) to distinguish between multiple implementations when necessary.
    Example:
@ActivityInterface
public interface MyActivity {
    void foo();
}

public class MyActivityImpl1 implements MyActivity, Runnable {
    // This is registered as MyActivity_foo activity name with the worker
    // This is exactly the current behavior
    public void foo() {
        // whatever
    }
    // This is not an activity method
    public void run() {
        //whatever
    }
}

@ActivityImplementation(type="MyActivity2")
public class MyActivityImpl2 implements MyActivity {
    // This is registered as MyActivity2_foo activity name with the worker
    public void foo() {
        // whatever
    }

}

worker.registerActivitiesImplementations(new MyActivityImpl1(), new MyActivityImpl2());


@WorkflowInterface
public interface MyWorkflow {
    @WorkflowMethod
    void execute();
}

public class MyWorkflowImpl implements MyWorklfow {

    MyActivity a1 = Workflow.newActivityStub(MyActivity.class);
    MyActivity a2 = Workflow.newActivityStub(MyActivity.class, "MyActivity2");
    // This is not valid as Runnable is not annotated with @ActivityInterface
    Runnable invalid = Workflow.newActivityStub(Runnable.class, "foo");
    MyActivity[] activities = new MyActivity[] {a1, a2};
    
    public void execute() {
        a1.foo(); // calls MyActivity_foo
        a2.foo(); // calls MyActivity2_foo
        for(MyActivity a: activities) {
           a.foo();  // Ends up calling MyActivity_foo and MyActivity2_foo activity names.
        }
    }
}

Note that both of the approaches are almost backwards compatible with the current implementation. The only incompatible change is requirement to annotate all activity definition interfaces with @ActivityInterface.

from sdk-java.

sdwr98 avatar sdwr98 commented on August 18, 2024

Is there a reason that you're looking solely at putting @ActivityImplementation at the class level rather than having an @ActivityMethod interface? I ask because for people coming to Cadence with existing code that they might be refactoring it might be helpful to mark just some of the methods in an interface as an available activity.

Regarding the qualifier for different activity implementations - we don't have a need for that, but it seems like a good idea for those who do.

from sdk-java.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.