Comments (3)
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.
- 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.
- 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.
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)
- NoClassDefFoundError: com/google/protobuf/GeneratedMessageV3 | Spring 3.3.1 HOT 4
- Add option to configure the deadline of `ChannelManager#getServerCapabilities` HOT 6
- Support "query" when listing schedules
- Test server should treat update/poll-update as long-poll HOT 1
- Better toString representations on service stub options
- Revisit local activity backpressure logic w/ no-max slot suppliers
- Generated Google proto classes are part of generated service client classes
- Support schedule search attribute update
- WorkflowTask failure because of an invalid state transition in LocalActivity state machine
- CI: Get rid of buildjet-2vcpu-ubuntu-1804 GHA runners
- Child workflow cancellation can trigger SDK event loop without a WFT Started
- Enable Nexus test server docker functional tests once 1.25 is released
- Workflow-init support HOT 1
- Include Package Version Information in manifest HOT 4
- Carry over search attributes on continue-as-new if none are explicitly specified
- Interceptor Configurations - exclusions based on workflow/activity type and task queue HOT 1
- Workflow.newExternalWorkflowStub HOT 4
- Type safe async update API
- Fix workflow start delay docs to say signal does not interrupt delay
- Schedules without a catch up window use the min catch up window instead of the default catch up window HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sdk-java.