<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://baba08.in/feed.xml" rel="self" type="application/atom+xml" /><link href="http://baba08.in/" rel="alternate" type="text/html" /><updated>2026-06-09T05:19:51+00:00</updated><id>http://baba08.in/feed.xml</id><title type="html">baba08</title><subtitle>Sohit Gore</subtitle><entry><title type="html">Temporal: Getting started with Java and Python</title><link href="http://baba08.in/jekyll/update/2024/06/08/temporal.html" rel="alternate" type="text/html" title="Temporal: Getting started with Java and Python" /><published>2024-06-08T01:55:22+00:00</published><updated>2024-06-08T01:55:22+00:00</updated><id>http://baba08.in/jekyll/update/2024/06/08/temporal</id><content type="html" xml:base="http://baba08.in/jekyll/update/2024/06/08/temporal.html"><![CDATA[<h2 id="introduction">Introduction</h2>

<p>In this blogpost I will demonstrate how temporal can be used to implement Workers based execution model accross different services.</p>

<p>Temporal provides durable execution. It maintains the state of functions, so that we can keep track of the function execution.</p>

<p>Functions can be registered as <code class="language-plaintext highlighter-rouge">Workflow</code> if they are more deterministic, or else if they have non-deterministic functionalities like http calls, they can be registered as <code class="language-plaintext highlighter-rouge">Activity</code></p>

<p>In this example we will create a <strong>Workflow in Java</strong> which will be picked by a <strong>Python worker</strong>.</p>

<p><br /></p>

<h2 id="installation">Installation</h2>

<p>Easiest way to install Temproal is via <code class="language-plaintext highlighter-rouge">docker-compose</code></p>

<p>Follow the below steps:</p>

<ul>
  <li>
    <p>Clone the repo: <a href="https://github.com/temporalio/docker-compose.git">https://github.com/temporalio/docker-compose.git</a></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">cd temporal/docker-compose</code></p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">docker compose up -d</code>
The default <code class="language-plaintext highlighter-rouge">docker-compose.yml</code> file uses <code class="language-plaintext highlighter-rouge">postgres</code>, you can use other docker compose files for using different databases that are supported eq. mysql</p>
  </li>
</ul>

<p>This will start the <code class="language-plaintext highlighter-rouge">Temporal Cluster</code> and some other dependencies like database and <code class="language-plaintext highlighter-rouge">elastic-search</code>. The cluster will listen on port <code class="language-plaintext highlighter-rouge">7233</code><br />
It will also start the UI which can be accessed on port <code class="language-plaintext highlighter-rouge">8080</code>.
<br /><br /></p>

<h2 id="implementation">Implementation</h2>

<p>This implementation will require the following components</p>

<ul>
  <li><strong>Python Worker</strong> which will execute the Activity</li>
  <li><strong>Java Workflow</strong> which will call for the execution of the python activity</li>
  <li><strong>Workflow Starter</strong> for the Java Workeflow and another <strong>Worker in Java</strong> which will execute the workflow code.</li>
</ul>

<p><br /></p>

<h3 id="writing-a-java-workflow">Writing a Java Workflow</h3>

<p>Include the temporal dependency.
If you are using <code class="language-plaintext highlighter-rouge">maven</code>, add below dependency to your <code class="language-plaintext highlighter-rouge">pom.xml</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;dependency&gt;
    &lt;groupId&gt;io.temporal&lt;/groupId&gt;
    &lt;artifactId&gt;temporal-sdk&lt;/artifactId&gt;
    &lt;version&gt;1.19.1&lt;/version&gt;
&lt;/dependency&gt;
</code></pre></div></div>

<p><br /></p>

<p>Create a Workflow Interface <code class="language-plaintext highlighter-rouge">SimpleWorkflow.java</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@WorkflowInterface
public interface SimpleWorkflow {

    @WorkflowMethod
    String simpleActivity(String value);
}
</code></pre></div></div>

<p><br /></p>

<p>Implement the <code class="language-plaintext highlighter-rouge">WorkflowInterface</code> in <code class="language-plaintext highlighter-rouge">SimpleWorkflowImpl.java</code></p>

<p>First create an <code class="language-plaintext highlighter-rouge">AcitvityStub</code>. <br />
The temporal <code class="language-plaintext highlighter-rouge">Worker</code> will communicate with the cluster using a task-queue and <strong>both the worker and workflow should be resgistered on the same task-queue.</strong></p>

<p><br /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ActivityOptions options =
    ActivityOptions.newBuilder()
        .setTaskQueue("simple-task-queue")
        .build();

private final ActivityStub externalActivity = Workflow.newUntypedActivityStub(options);
</code></pre></div></div>

<p>Since we will create our Worker in <code class="language-plaintext highlighter-rouge">Python</code>, we register the Activity using <code class="language-plaintext highlighter-rouge">newUntypedActivityStub</code>
<br /></p>

<p>Next, lets implement the <code class="language-plaintext highlighter-rouge">WorkflowMethod</code> and call for the execution of python activity</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@Override
public String SimpleActivity(String name) {

    String result = 
        externalActivity.execute("PythonActivity", String.class, name);
    
    return result;        
}
</code></pre></div></div>
<p>We will name our activity in python code as <code class="language-plaintext highlighter-rouge">PythonActivity</code></p>

<p><br /></p>

<h3 id="writing-the-workerflow-starter-and-java-worker-code">Writing the Workerflow Starter and Java Worker code</h3>

<p>We will write workerflow starter and Java worker code in the same file <code class="language-plaintext highlighter-rouge">WorkflowStarter.java</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>package simpleWorkflow

import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;

public class WorkflowStarter {

    public static final String TASK_QUEUE = "java-task-queue";

    public static void main(String[] args) throws Exception {

        WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();

        WorkflowClient client = WorkflowClient.newInstance(service);
        
        WorkflowOptions options = WorkflowOptions.newBuilder()
            .setWorkflowId("simple-workflow")
            .setTaskQueue(TASK_QUEUE)
            .build();


        WorkerFactory factory = WorkerFactory.newInstance(client);

        // create a new worker
        Worker worker = factory.newWorker(TASK_QUEUE);

        // register the java workflow
        worker.registerWorkflowImplementationTypes(SimpleWorkflowImpl.class);

        // start the worker
        factory.start();

        System.out.println("Started the Worker, starting workflow...");

        SimpleWorkflow workflow = client.newWorkflowStub(SimpleWorkflow.class, options);

        // execute the workflow
        String result = workflow.pythonActivity(args[0]);

        String workflowId = WorkflowStub.fromTyped(workflow).getExecution().getWorkflowId();

        factory.shutdown();

    }
}
</code></pre></div></div>

<p>In the above code,</p>
<ul>
  <li>we registered the Workerflow on <code class="language-plaintext highlighter-rouge">java-task-queue</code> with locally running Temporal instance.</li>
  <li>Started a Java worker listening on <code class="language-plaintext highlighter-rouge">java-task-queue</code></li>
  <li>Started the Workflow. The Java worker should pick the task, execute the workflow which will in turn call the python activity.</li>
</ul>

<p><br /></p>

<h3 id="writing-the-python-worker">Writing the Python Worker</h3>

<p>Finally we need the Python worker to execute the python activity. <br />
We will define the activity and write the worker in the same file <code class="language-plaintext highlighter-rouge">python_worker.py</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@activity.defn(name="PythonActivity")
async def simple_activity(name: str) -&gt; str:
    print(f"Hello {name}")
    return "Success"


async def main():
    temporal_client = await client.Client.connect("localhost:7233")

    python_worker =  worker.Worker(
        client=temporal_client,
        task_queue="simple-task-queue",
        activities=[simple_activity],
    )
    await python_worker.run()

if __name__ == "__main__":
    asyncio.run(main())

</code></pre></div></div>

<p>In the above code,</p>
<ul>
  <li>we registered the worker on the locally running Temporal instance and listening on queue <code class="language-plaintext highlighter-rouge">simple-task--queue</code></li>
  <li>We defined the activity and registered the acitvity with the worker.</li>
</ul>

<p><br /><br /></p>

<h2 id="execution">Execution</h2>

<p>In the final step we will execute the two programs,</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">WorkflowStarter.java</code></li>
  <li><code class="language-plaintext highlighter-rouge">python_worker.py</code></li>
</ul>

<p>In different terminals execute the programs.</p>

<p>First start the python worker</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python python_worker.py
</code></pre></div></div>

<p>Next execute the java program</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mvn compile exec:java -Dexec.mainClass="simpleWorkflow.WorkflowStarter" -Dexec.ar
gs="Sohit"
</code></pre></div></div>

<p>The execution can be monitored on <code class="language-plaintext highlighter-rouge">localhost:8080</code></p>

<p><br /><br /></p>

<h2 id="conclusion">Conclusion</h2>

<p>Temporal helps execute the code using workers easily. We can have multiple workers listening on the same taskQueue and temporal will take care of the distribution of the tasks.</p>

<p>Complete code can be found at: <a href="https://github.com/Sohit1212/temporal-polyglot">https://github.com/Sohit1212/temporal-polyglot</a></p>]]></content><author><name></name></author><category term="jekyll" /><category term="update" /><summary type="html"><![CDATA[Introduction]]></summary></entry></feed>