Signals Vs ActivityCompletionClient

I think you are confusing activities with operations that are executed by external entities like humans.

If all you want is to execute three activities in a sequence then just invoke them synchronously one after another:

activities.activity1();
activities.activity2();
activities.activity3();

The activity + reply signal pattern is needed when the actual work is done by an external system. For example, an existing REST service exposes an endpoint to initiate some action and then later delivers the result through a webhook. In this case, an activity is used to call the REST endpoint and the webhook uses the signal to notify the workflow about the completion. The same applies to a human task. An activity is used to enqueue the task to an external task management system and the signal is used to notify workflow about task completion.

Q2: To find if an activity is done executing its task, other than signals another alternative is to use ActivityCompletionClient. So in what type of use-cases are Signals preferred to ActivityCompletionClient and vice-versa. Are Signals for sequential activities, whereas ActivityCompletionClient for async ones?

In some cases the actual activity implementation is asynchronous. For example, you want to use a custom separate thread pool to execute an activity. Then you can disconnect the activity from its original function (through Activity.getExecutionContext().doNotCompleteOnReturn) and later complete it asynchronously through the ActivityCompletionClient. Note that in this case the timeouts and retry policy applies to the whole activity. So it is a very bad fit for manual tasks which can take days.

For async activity implementation that is local to a process, we recommend using ActivityExecutionContext.useLocalManualCompletion as it is much simpler to use than doNotCompleteOnReturn.