From Temporal’s point of view, scheduling an activity only requires the activity's name (which we formally call the "activity type") and its task queue; the Temporal server itself doesn't "need" the activity function, nor care in which language is it coded.
The easiest way for your Python workflow to invoke a TypeScript activity is therefore to simply provide the correct activity type, as a string, to the execute_activity function, as well as the task queue name (plus any other args/options you would otherwise want to pass). From the workflow's perspective, it makes no difference that the activity is implemented in a different language, except for the fact that it can't benefit from type safety checks that having an actual function definition allows.
For example, you might do this in your workflow:
@workflow.run
async def run(self, name: str) -> str:
return await workflow.execute_activity(
"composeGreeting",
ComposeGreetingInput("Hello", name),
start_to_close_timeout=timedelta(seconds=10),
task_queue="typescript-activities",
)
and then, start a TypeScript worker listening on task queue "typescript-activities", with the following activity:
async function composeGreeting(input: ComposeGreetingInput): Promise<string> {
return input.items.join(" ");
}
Alternatively, it is also possible to define a stub function on your workflow side, to make cross-language activity calls looks more like regular, same-language activity calls. For example:
@workflow.run
async def run(self, name: str) -> str:
return await workflow.execute_activity(
compose_greeting,
ComposeGreetingInput("Hello", name),
start_to_close_timeout=timedelta(seconds=10),
task_queue="typescript-activities",
)
@activity.defn(name="composeGreeting")
async def compose_greeting(name: ComposeGreetingInput) -> str:
# This function is meant to be a stub; it doesn't need to be registered
# as an activity on a worker, and it will never get called. You however
# need to make sure that this function's signature exactly matches that
# of its TypeScript counterpart. Note the `name="composeGreeting"` arg
# on the decorator above. That means that the activity type will be
# `composeGreeting` (following the TS convention), rather than
# `compose_greeting`, which is the name of this Python function and
# would therefore have been the default workflow type.
return f""
A few things to consider:
- You will need a different task queue for your Python activities vs TS activities
- Different languages have different conventions regarding function naming, and different SDKs may have different rules regarding how function names relate to activity types. When doing activity call across SDK, you may need to force the activity type on the activity worker, or use the correct syntax of the Activity Type on the Workflow side.
- SDKs should generally encode/decode args and return values correctly, but cross-SDK calls may expose differences in how various JSON libraries handle some particular cases. You should therefore be more cautious in defining your data structures. Only use simple types that are natively understood by JSON. Beware of “big integers”, dates, and similar.
- Similarly, SDK will correctly route errors thrown from activities back to the Workflow. You may however note some discrepancies in how “language native” errors get encoded/decoded. Make sure you test error handling properly.
subprocesspython module, ofc. that I am not considering some "data interaction" between those scripts. So the flow that comes to my mind is, python -> bash -> JavaScript.temporal-workflow, which is an open source workflow-as-code platform (temporal.io). Indeed, OP should have indicated this more clearly, as the question can't make sense outside of that specific context.