Exception when creating workflow Stub in Activity

Getting Exception: The following exception when I am trying to create workflow stub within an Activity.
I did start the workflow and Worker.

Please help…

java.lang.IllegalStateException: Null workflowId. Was workflow started?
at io.temporal.internal.sync.WorkflowStubImpl.checkStarted(WorkflowStubImpl.java:370)
at io.temporal.internal.sync.WorkflowStubImpl.signal(WorkflowStubImpl.java:88)
at io.temporal.internal.sync.WorkflowInvocationHandler$SyncWorkflowInvocationHandler.signalWorkflow(WorkflowInvocationHandler.java:297)
at io.temporal.internal.sync.WorkflowInvocationHandler$SyncWorkflowInvocationHandler.invoke(WorkflowInvocationHandler.java:274)
at io.temporal.internal.sync.WorkflowInvocationHandler.invoke(WorkflowInvocationHandler.java:178)
at com.sun.proxy.$Proxy12.setCustomActivityId(Unknown Source)
at io.workshop.c1intro.AccountActivitiesImpl.notify(AccountActivitiesImpl.java:53)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)


Activity Code:
public class AccountActivitiesImpl implements AccountActivities {

public static final WorkflowServiceStubs service = WorkflowServiceStubs.newInstance();
public static final WorkflowClient client = WorkflowClient.newInstance(service);
public static final String taskQueue = "myTaskQueue";

NotifyUserAccounts workflow;

@Override
public String notify(String accountId) throws Exception{

// try {
// // simulate some time…
// Thread.sleep(2 * 1000);
// } catch (Exception e) {
// e.printStackTrace();
// }

    workflow = client.newWorkflowStub(
            NotifyUserAccounts.class,
            WorkflowOptions.newBuilder()
                    .setWorkflowId(Activity.getExecutionContext().getInfo().getWorkflowId())
                    .setTaskQueue(taskQueue)
                    .build());



    workflow.setCustomActivityId("someName","someId");

    return "notified...";
}

}

Hello @Krishnendu_Kunti

can you try using the following overloaded method

       NotifyUserAccounts greetingWorkflow =
           client.newWorkflowStub(NotifyUserAccounts.class, workflowId);

You want to create a workflow stub with workflow options when the stub is used to start a workflow execution.

Also,
public String notify(String accountId) throws Exception{
signaling a workflow is an async operation, the client will never get the exception thrown by this method.

Antonio

Thank you Antonio , it did work :slightly_smiling_face:.

Can you please clarify the later statement, is it that Signal will be sent via a separate thread hence any exception encountered while sending the signal will not be caught in the activity Implementation method.

However such exception will be caught in in the signal method.

Thanks again
Krishnendu

@Krishnendu_Kunti signalWorkflow is a request that the server persists once it receives it. You will get an exception if the client can not connect to the server or the workflow execution does not exist …

The worker running the workflow execution (the one you are signaling), is continuously polling for task to execute. If it has pollers and slots available to execute workflowTasks, the worker will pull the task and deliver the signal to the workflow execution.

let me know if it helps

In your case, it looks like you are signaling the same workflow execution. What is your use case if I can ask?

Thanks,

Hi @antonio.perez

Thanks for the clarification. We have a scenario where we will be using same activity more than once , where we want to display the activity with different Name.

Say we have a DB table migrate activity with method migrate , instead of calling this migrate every time we would like to show it as migrate_table1, migrate_2… etc.

We plan to achieve it by saving the activity Id and Activity given name in custom search attribute. Since we cant update search attribute inside an activity we plan to sent the details to workflow before we start an activity.

Since we will send the name / id using Signal even before we stat the Activity the Workflow instance should be available.

Thank you
Krishnendu

Updating search attributes on each activity puts an additional load on ES and can limit scalability.

You can use DynamicActivity to implement an activity of any type and Workflow.newUntypedActivityStub.execute to invoke it.

Hi @maxim

The requirement here is to capture same activity with different names (which I think is not possible using Dynamic Activity), Temporal already has an enhancement identified for the same.

Thank you
Best Regards
Krishnendu

@Krishnendu_Kunti

see this example samples-java/HelloDynamic.java at 4db79e0f91e2b4b58528bd26bda6b0dc6f5fc2dc · temporalio/samples-java · GitHub

to test it you can replace the line above with something like

      activity.execute("activity1", String.class, greeting, name, type);
      activity.execute("activity2", String.class, greeting, name, type);

The workflow history will record activity1 and activity2 respectively,

And you can implement DynamicGreetingActivity to execute different code based on Activity.getExecutionContext().getInfo().getActivityType() value

Thank you @antonio.perez .

I was able to test out Dynamic activity and it works as mentioned, however here is the problem statement:

  1. We have existing library of activities, which users would include in their workflows , however some users might want to capture those activities with different Names. For instance there is an activity called migrate_table , but in context of workflow user may want to name it as migrate_Employee_table.

  2. If we use Dynamic activity then I am assuming that Dynamic activity will form a Wrapper and internally call migrate_table code.

  3. It is possible to write such a generic wrapper but the input parameter mapping needs to be coded explicitly for each such call , hence an overhead for the user (which we do not want).

Currently we are saving given activity name and activity Id as search parameters.

Please suggest what will be a good design to handle this requirement.

Thanks again for all the help.
Krishnendu

Hi @antonio.perez

Need one help, I have created the following untyped stub (inside an Activity) and tried call signal method in workflow. … I am getting the following exception:

WorkflowStub wrkflowstb = client.newUntypedWorkflowStub(Activity
.getExecutionContext().getInfo().getWorkflowId());

ActivityId=11def5c0-d577-361e-9cf4-2dc4cc153f68, activityType=Subset Sum, attempt=3
io.temporal.client.WorkflowNotFoundException: workflowId=‘Modeln_Performance Flow_f0fe565e-e0e2-4214-a585-c7a31c24624d’, runId='}

Please let me know if I am missing something…

Thanks in advance
Krishnendu

@Krishnendu_Kunti do you have more than one namespace?

Hi @antonio.perez Yes thats correct we have couple of namespaces… is there a way to set it in stub…

@Krishnendu_Kunti

Namespace is set to the client, WorkflowClientOptions , before creating the stub

      WorkflowClient client =
          WorkflowClient.newInstance(
              service, WorkflowClientOptions.newBuilder()
.setNamespace("your-namespace").build());

Thanks for the help @antonio.perez :slightly_smiling_face:

I understand that you want to make this transparent to the user?

Yes @antonio.perez that’s correct.

I am willing to implement this feature:

Pluggable activity name provider · Issue #396 · temporalio/sdk-java (github.com)

Please let me know…

Thank you
Best Regards
Krishnendu

@Krishnendu_Kunti feel free to comment on the issue if you want to contribute.

To make this transparent to the user, you could have a class wrapping the invocation to the DynamicActivity implementation.

      MyDynamicActivityExecutor myActivityExecutor = new MyDynamicActivityExecutor();
      myActivityExecutor.execute1(greeting, name);
      myActivityExecutor.execute2(greeting, name);

and MyDynamicActivityExecutor

  ActivityStub activity =
      Workflow.newUntypedActivityStub(
          ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build());
  public void execute1(String greeting, String name) {
    activity.execute("activity1", String.class, greeting, name);
  }

@Krishnendu_Kunti also see this comment
Pluggable activity name provider · Issue #396 · temporalio/sdk-java · GitHub

Thanks a lot for the inputs @antonio.perez .
Best Regards
Krishnendu