Hello World with Temporal

Hello World with Temporal

The first of all dev app with Golang

Requirements

Install Temporal

https://docs.temporal.io/dev-guide/go/foundations#add-your-sdk

Start Temporal dev server

$ temporal server start-dev

Access Temporal UI

Go to URL http://localhost:8233/

Create a basic Go app

  1. Create project folder <project>

  2. Initialize go app go mod init

  3. Create main.go

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello World!")
}

Well, that is a first Go Hello World.

Add Temporal SDK

Install go dependency

$ go get go.temporal.io/sdk

Create a Workflow Definition

I'll explain Temporal concepts later. For now, a Workflow Definition is a Golang function with this signature func Name(ctx workflow.Context, <params>) (<returns>, error)

So edit main.go to add the Workflow Definition that prints Hello World

package main

import (
    "fmt"
)

func Workflow(ctx workflow.Context) error {
    fmt.Println("Hello World!")
    return nil
}

func main() {
    // fmt.Println("Hello World!")
}

Edit main function to start a Worker

A Worker is a process that will listen to events and act on them. It will receive commands from the Temporal server and execute a Workflow Definition that is registered for that process.

For this example:

  1. We create a client that connects to the local development Temporal cluster

  2. Register a Workflow Definition

  3. Waits for a SIGTERM signal to stop the worker

So:

package main

import (
    "fmt"
    "log"

    "go.temporal.io/sdk/client"
    "go.temporal.io/sdk/worker"
    "go.temporal.io/sdk/workflow"
)

func Workflow(ctx workflow.Context) error {
    fmt.Println("Hello World!")
    return nil
}

func main() {
    // Create a Temporal Client
    // A Temporal Client is a heavyweight object that should be created just once per process.
    client, err := client.Dial(client.Options{})
    if err != nil {
        log.Fatalln("Unable to create client", err)
    }
    defer client.Close()
    // Create a new Worker.
    yourWorker := worker.New(client, "task-queue", worker.Options{})

    // Register Workflow Definition
    yourWorker.RegisterWorkflow(Workflow)

    // Wait for interruption
    err = yourWorker.Run(worker.InterruptCh())
    if err != nil {
        log.Fatalln("Unable to start Worker", err)
    }
}

Running this main.go :

$ go run main.go
2023/09/27 17:42:01 INFO  No logger configured for temporal client. Created default one.
2023/09/27 17:42:01 INFO  Started Worker Namespace default TaskQueue task-queue WorkerID 71190@localhost.local@

Ok, so you get a Worker process running, that will handle events from task-queue and it will execute a Workflow Definition.

Starting a Workflow

For this, let's use the CLI, in another terminal session:

$ temporal workflow start --task-queue task-queue --type Workflow
Running execution:
  WorkflowId  52f8a61f-ac78-4f80-ace1-3c5ba32b8b63
  RunId       7e6411cb-dd8c-4879-a200-46d5b157f9c8
  Type        Workflow
  Namespace   default
  TaskQueue   task-queue
  Args        []

And you will get at the worker terminal

❯ go run .
2023/09/27 17:42:01 INFO  No logger configured for temporal client. Created default one.
2023/09/27 17:42:01 INFO  Started Worker Namespace default TaskQueue task-queue WorkerID 71190@localhost.local@
Hello World!

Temporal UI

In the browser (http://localhost:8233/)

You can see the entry for a Workflow Execution, with its ID and other meta information.

That is it!

Well, the basic basic basic basic example.

For the next posts, I will explain the Temporal Concepts and we are going to incrementally improve this example.

References