Throwing exception while registering activity in worker

I have two activity interface with the same method name,

@ActivityInterface
  public interface GreetingActivities {
    String composeGreeting(String greeting, String name);
  }

  @ActivityInterface
  public interface GreetingActivities2 {
    String composeGreeting(String greeting, String name);
  }

Below find the implementations of the same,

static class GreetingActivitiesImpl implements GreetingActivities {
    @Override
    public String composeGreeting(String greeting, String name) {
      return greeting + " " + name + "!";
    }
  }

  static class GreetingActivitiesImpl2 implements GreetingActivities2 {

    @Override
    public String composeGreeting(String greeting, String name) {
      System.out.println("Activity 2");
      return "Some Value!!!";
    }
  }

worker.registerActivitiesImplementations(new GreetingActivitiesImpl(), new GreetingActivitiesImpl2());

while I am registering the activities in worker I am getting below exception.

Exception in thread "main" java.lang.IllegalArgumentException: "ComposeGreeting" activity type is already registered with the worker
	at io.temporal.internal.sync.POJOActivityTaskHandler.registerActivityImplementation(POJOActivityTaskHandler.java:116)
	at io.temporal.internal.sync.POJOActivityTaskHandler.registerActivityImplementations(POJOActivityTaskHandler.java:179)
	at io.temporal.internal.sync.SyncActivityWorker.registerActivityImplementations(SyncActivityWorker.java:55)
	at io.temporal.worker.Worker.registerActivitiesImplementations(Worker.java:326)
	at io.temporal.samples.hello.HelloActivity2.main(HelloActivity2.java:195)

Hi @anil_kumble
Activity types are by default registered with their method name (with first character upper-cased).
You are getting this error because you are registering two Activity types with the same name, namely “ComposeGreeting” corresponding to your two “composeGreeting” activity methods in the two Activity interfaces.

You have a couple of options:

  1. Rename one of your “composeGreeting” methods (keeping them unique) in your Activity interface and its corresponding impl.

  2. Define an Activity name prefix, for example:

    @ActivityInterface(namePrefix = “one”)
    public interface GreetingActivities {
    String composeGreeting(String greeting, String name);
    }

    @ActivityInterface(namePrefix = “two”)
    public interface GreetingActivities2 {
    String composeGreeting(String greeting, String name);
    }

  3. Define unique Activity type name using the ActivityMethod interface, for example:

    @ActivityInterface
    public interface GreetingActivities {
    @ActivityMethod(name = “composegreetingone”)
    String composeGreeting(String greeting, String name);
    }

    @ActivityInterface
    public interface GreetingActivities2 {
    @ActivityMethod(name = “composegreetingtwo”)
    String composeGreeting(String greeting, String name);
    }

  4. Use a combination of 2. and 3.

Hope this helps!

Thanks for the response!!

This will help when I have two different ActivityInterfaces.

If I have two different implementations for the single ActivityInterface how can I differentiate the ActivityMethod on run time?

Is there any option to update ActivityMethod on run time programmatically?

Each of the Activity impls you register with your Worker will need its own interface, but you can use interface inheritance for common methods, for example:

public interface BaseActivities {
  String composeGreeting(String greeting, String name);
}
@ActivityInterface(namePrefix = "one")
public interface MyActivities extends BaseActivities {
  // custom activity methods here...
}
@ActivityInterface(namePrefix = "two")
public interface MyOtherActivities extends BaseActivities {
  // custom activity methods here...
}

You would register both impls with Worker, and in your workflow have two Activity Stubs to differentiate.

Is there any option to update ActivityMethod on run time programmatically?

Check out
Workflow.newUntypedActivityStub

you mean that each activity interface will have a single implementation. I think it is violating the basic principle of having an interface. A need for an interface will arrive If we require multiple implementations of it. If it is single then we could have it just as a class right instead of having an interface and implementing it?

I don’t know how to use it. Please give some examples?

A small doubt that can we have different activity options for the methods kept in the activity interface. As of now, I can see activity options are specified to the whole interface.

Like this,

Workflow.newActivityStub(
GreetingActivities.class,
ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(2)).build());

What if I need different closeTimeout, heartbeat time out for my activity methods

you mean that each activity interface will have a single implementation. I think it is violating the basic principle of having an interface. A need for an interface will arrive If we require multiple implementations of it. If it is single then we could have it just as a class right instead of having an interface and implementing it?

It has multiple implementations. One is actual activity implementation, another is the activity stub which is used to invoke an activity from the workflow code.

A small doubt that can we have different activity options for the methods kept in the activity interface. As of now, I can see activity options are specified to the whole interface.

It is possible to specify activity options per activity type through WorkflowImplementationOptions.setActivityOptions and Workflow.newActivityStub. But these features are not released yet.

Are you referring this?

@ActivityInterface
public interface GreetingActivities {
@ActivityMethod(name = “greet”)
String composeGreeting(String greeting, String language);
}

Here, it is done at compile time. I what this needs to be accomplished at run time via programmatically.
I didn’t see any other options other than this in the doc.

Could you explain what exactly are you trying to achieve by “what this needs to be accomplished at run time via programmatically.”. Are you planning to implement activities dynamically?

No it doesn’t have multiple implementations,
If you see the example HelloActivity where we have single activity interface called GreetingActivities and it has only one implementation called GreetingActivitiesImp.

private final GreetingActivities activities =
Workflow.newActivityStub(
GreetingActivities.class,
ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(30)).build());

The above code is not an implementation of an activity interface, it just a instantiation.

Yes, we are planning to implement our activities dynamically

The above code is not an implementation of an activity interface, it just a instantiation.

It is an instantiation of another activity implementation which is a stub that is used to schedule an activity.

Yes, we are planning to implement our activities dynamically

Then use DynamicActivity.

Oh… we have dynamic activity as a separate feature. I didn’t notice it in the temporal doc. Could you please share me the doc. And also sample java example for that

It is a new feature, so no document or sample. See the class JavaDoc.

And one more doubt that, since it is restricted to single implementation of a ActivityInterface, Why it is designed to create an interface and implement it. Instead we could have it as a class where we can annotate the class with ActivityInterface, right?

The basic idea of having an interface is to have multiple variety of implementations of the method right ? But here it is a single implementation of an interface, That’s why still I’m confusing

Workflow code needs to know only the activity interface to invoke it. It doesn’t need to know the activity implementation which can be running in a different process (or even be implemented in a different language like Go).

So the interface was used to specify the signature of an activity without a specific implementation details.

Okay, let me go through it, Also if any other new feature not listed in the doc kindly just add the Java Doc link end of the doc so that it will not be missed.

import io.temporal.activity.ActivityInterface;
import io.temporal.activity.ActivityOptions;
import io.temporal.activity.DynamicActivity;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.common.converter.EncodedValues;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
import java.time.Duration;

public class DynamicActivityExample {

static final String DYNAMIC_TASK_QUEUE = “DynamicActivityTaskQueue”;

@WorkflowInterface
public interface SampleWorkflow {
@WorkflowMethod
String sampleMethod();
}

@ActivityInterface
public interface TestDynamicActivity extends DynamicActivity {}

public static class SampleWorkflowImpl implements SampleWorkflow {

private final TestDynamicActivity activities =
    Workflow.newActivityStub(
        TestDynamicActivity.class,
        ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(40)).build());

@Override
public String sampleMethod() {

  EncodedValues encodedValues = new EncodedValues("val1", "val2");
  activities.execute(encodedValues);

  return "value";
}

}

static class TestDynamicActivityImpl implements TestDynamicActivity {

@Override
public Object execute(EncodedValues args) {
  System.out.println("execute");
  return "execute";
}

}

public static void main(String args) {

WorkflowServiceStubs service = WorkflowServiceStubs.newInstance();
WorkflowClient client = WorkflowClient.newInstance(service);

WorkerFactory factory = WorkerFactory.newInstance(client);
Worker worker = factory.newWorker(DYNAMIC_TASK_QUEUE);

worker.registerWorkflowImplementationTypes(SampleWorkflowImpl.class);
worker.registerActivitiesImplementations(new TestDynamicActivityImpl());

factory.start();

SampleWorkflow workflow =
    client.newWorkflowStub(
        SampleWorkflow.class,
        WorkflowOptions.newBuilder()
            .setWorkflowId("WORKFLOW_ID_1")
            .setTaskQueue(DYNAMIC_TASK_QUEUE)
            .build());

System.out.println("starting workflow");
System.out.println(workflow.sampleMethod());
System.exit(0);

}
}

Is this the right way to test dynamic activity.

Here I created an interface intermediately else it is throwing below error

Missing required @ActivityInterface annotation:

An implementation of DynamicActivity should not use @ActivityInterface annotation.

And it can be invoked using any other interface annotated with @ActivityInterface or using an untyped stub created through Workflow.newUntypedActivityStub.