April 27, 2023

Using the Temporal CLI

Loren Sands-Ramshaw

Loren Sands-Ramshaw

In the Server 1.20 release we announced a new Temporal CLI, and we also released an interview and blog post with more info about it and its history.

The tl;dr is we combined our efforts on:

to create a single temporal command-line tool that lets you both:

  • run a development version of the Server
  • interact with the Server

We recommend switching to temporal for development and testing, and recommend using it for production scripts once we release v1 (coming soon). We will continue supporting tctl for two more Server releases (through 1.22).

In this post, you’ll learn how to use temporal.

Contents:

Installing

cURL

curl -sSf https://temporal.download/cli.sh | sh

Homebrew

brew install temporal

Manual

You can also manually download, extract, and add to PATH the latest binary for your CPU architecture.

Running the Server

temporal server start-dev

This:

By default, it doesn’t persist your data—if you start a Workflow, Ctrl-C, and run the command again, your Workflow will be gone.

If you'd like your Workflows to be saved, use the --db-filename flag:

temporal server start-dev --db-filename temporal.db

Interacting with the Server

In another terminal, you can run commands to interact with the Server. This command starts a Workflow:

$ temporal workflow start \
  --task-queue hello-world \
  --type MyWorkflow \
  --workflow-id 123 \
  --input 456

Running execution:
  WorkflowId                                   123
  RunId       357074e4-0dd8-4c44-8367-d92536dd0943
  Type        MyWorkflow
  Namespace   default
  TaskQueue   hello-world
  Args        [456]

The shorthand options are:

temporal workflow start -t hello-world --type MyWorkflow -w 123 -i 456

You can also list and describe Workflows:

$ temporal workflow list

  Status   WorkflowId     Name       StartTime
  Running         123  MyWorkflow  14 seconds ago

$ temporal workflow describe --workflow-id 123

{
  "executionConfig": {
    "taskQueue": {
      "name": "hello-world",
      "kind": "Normal"
    },
    "workflowExecutionTimeout": "0s",
    "workflowRunTimeout": "0s",
    "defaultWorkflowTaskTimeout": "10s"
  },
  "workflowExecutionInfo": {
    "execution": {
      "workflowId": "123",
      "runId": "357074e4-0dd8-4c44-8367-d92536dd0943"
    },
    "type": {
      "name": "MyWorkflow"
    },
    "startTime": "2023-04-15T06:42:31.191137Z",
    "status": "Running",
    "historyLength": "2",
    "executionTime": "2023-04-15T06:42:31.191137Z",
    "memo": {

    },
    "autoResetPoints": {

    },
    "stateTransitionCount": "1"
  },
  "pendingWorkflowTask": {
    "state": "Scheduled",
    "scheduledTime": "2023-04-15T06:42:31.191173Z",
    "originalScheduledTime": "2023-04-15T06:42:31.191173Z",
    "attempt": 1
  }
}

When listing, you can get more Workflow fields and output in JSON:

$ temporal workflow list --fields long --output json

[
  {
    "execution": {
      "workflow_id": "123",
      "run_id": "357074e4-0dd8-4c44-8367-d92536dd0943"
    },
    "type": {
      "name": "MyWorkflow"
    },
    "start_time": "2023-04-15T06:42:31.191137Z",
    "status": 1,
    "execution_time": "2023-04-15T06:42:31.191137Z",
    "memo": {},
    "task_queue": "hello-world"
  }
]

Filter out just the type with jq:

$ temporal workflow list --fields long -o json | jq '.[].type.name'

"OtherWorkflow"
"MyWorkflow"
"MyWorkflow"

And count how many Workflows of each type you have:

$ temporal workflow list --fields long -o json | jq '.[].type.name' | uniq -c

   1 "OtherWorkflow"
   2 "MyWorkflow"

For a list of common commands, see our CLI cheatsheet.

To see what else you do to Workflows, run:

$ temporal workflow 

NAME:
   temporal workflow - Operations that can be performed on Workflows.

COMMANDS:
   start        Starts a new Workflow Execution.
   execute      Start a new Workflow Execution and prints its progress.
   describe     Show information about a Workflow Execution.
   list         List Workflow Executions based on a Query.
   show         Show Event History for a Workflow Execution.
   query        Query a Workflow Execution.
   stack        Query a Workflow Execution with __stack_trace as the query type.
   signal       Signal Workflow Execution by Id or List Filter.
   count        Count Workflow Executions (requires ElasticSearch to be enabled).
   cancel       Cancel a Workflow Execution.
   terminate    Terminate Workflow Execution by Id or List Filter.
   delete       Deletes a Workflow Execution.
   reset        Resets a Workflow Execution by Event Id or reset type.
   reset-batch  Reset a batch of Workflow Executions by reset type (LastContinuedAsNew), FirstWorkflowTask), LastWorkflowTask
   trace        Trace progress of a Workflow Execution and its children.
   help, h      Shows a list of commands or help for one command

And here are all the top-level commands:

$ temporal

NAME:
   temporal - Temporal command-line interface and development server

USAGE:
   temporal [global options] command [command options] [arguments...]

VERSION:
   0.8.0 (server 1.20.1) (ui 2.13.3)

COMMANDS:
   server      Commands for managing the Temporal Server.
   workflow    Operations that can be performed on Workflows.
   activity    Operations that can be performed on Workflow Activities.
   task-queue  Operations performed on Task Queues.
   schedule    Operations performed on Schedules.
   batch       Operations performed on Batch jobs.
   operator    Operations performed on the Temporal Server.
   env         Manage environmental configurations on Temporal Client.
   completion  Output shell completion code for the specified shell (zsh, bash).
   help, h     Shows a list of commands or help for one command

You can read more about each by running temporal <command> or reading the CLI docs.

Environments

So far, the CLI has been talking to the Server at the default address, localhost:7233. To talk to another Server, like a production namespace on Temporal Cloud:

  1. Create an environment named prod.
  2. Pass --env prod to commands, like temporal workflow list --env prod.

To create a new environment, start setting its properties:

temporal env set prod.namespace production.f45a2
temporal env set prod.address production.f45a2.tmprl.cloud:7233
temporal env set prod.tls-cert-path /temporal/certs/prod.pem
temporal env set prod.tls-key-path /temporal/certs/prod.key

Check that you set them correctly:

$ temporal env get prod

  address        production.f45a2.tmprl.cloud:7233
  namespace      production.f45a2
  tls-cert-path  /temporal/certs/prod.pem
  tls-key-path   /temporal/certs/prod.key

If they’re correct, then this shouldn’t log a connection error:

$ temporal workflow list --env prod

For the full list of properties you can set, see the below options:

$ temporal env set -h

OPTIONS:
   Client Options:

   --address value                          The host and port (formatted as host:port) for the Temporal Frontend Service. [$TEMPORAL_CLI_ADDRESS]
   --codec-auth value                       Sets the authorization header on requests to the Codec Server. [$TEMPORAL_CLI_CODEC_AUTH]
   --codec-endpoint value                   Endpoint for a remote Codec Server. [$TEMPORAL_CLI_CODEC_ENDPOINT]
   --context-timeout value                  An optional timeout for the context of an RPC call (in seconds). (default: 5) [$TEMPORAL_CONTEXT_TIMEOUT]
   --env value                              Name of the environment to read environmental variables from. (default: "default")
   --grpc-meta value [ --grpc-meta value ]  Contains gRPC metadata to send with requests (format: key=value). Values must be in a valid JSON format.
   --namespace value, -n value              Identifies a Namespace in the Temporal Workflow. (default: "default") [$TEMPORAL_CLI_NAMESPACE]
   --tls-ca-path value                      Path to server CA certificate. [$TEMPORAL_CLI_TLS_CA]
   --tls-cert-path value                    Path to x509 certificate. [$TEMPORAL_CLI_TLS_CERT]
   --tls-disable-host-verification          Disables TLS host name verification if already enabled. (default: false) [$TEMPORAL_CLI_TLS_DISABLE_HOST_VERIFICATION]
   --tls-key-path value                     Path to private certificate key. [$TEMPORAL_CLI_TLS_KEY]
   --tls-server-name value                  Provides an override for the target TLS server name. [$TEMPORAL_CLI_TLS_SERVER_NAME]

   Display Options:

   --color value  when to use color: auto, always, never. (default: "auto")

For example, to set --codec-endpoint, you would do:

$ temporal env set prod.codec-endpoint localhost:3000

Aliases

If you like aliases, here’s what I have in my ~/.bash_profile:

alias t='temporal'
alias tw='temporal workflow'
alias ts='temporal server start-dev'
alias tsdb='temporal server start-dev --db-filename ~/temporal.db'

# send process to background so you can continue using the terminal
alias tsbg='temporal server start-dev &> /dev/null & disown'

You can also set up auto-completion for zsh or bash.

Upgrading

If you’re moving from tctl, here are the major changes to be aware of:

Global changes

  • New pagination mechanism with OS level tools such as less or more. Controlled by --pager or $PAGER. details
  • Most commands can format the output as a table or JSON using the --output option. details
  • You can limit the number of items when listing workflows, namespaces, etc. with, e.g. --limit 10.
  • DateTime formatting. details
  • All command and flag names now use hyphen - as delimiter instead of underscore _. details
  • --color option to choose when to enable/disable output coloring. Adds JSON coloring by default in TTY. details
  • env feature to manage CLI environments and change CLI options defaults. details
  • Updated the semantics of the commands and flags for consistency.
  • All global flags are moved under each command.

Specific changes

  • namespace, search-attribute, and cluster former top-level commands are now under temporal operator (these are meant for self-hosted Clusters, not Temporal Cloud).
  • Some commands are renamed: namespace register ➡️ namespace create, search-attribute add ➡️ search-attribute create
  • Added new command server start-dev!

Future

0.8.0 is the current version, and we have just a few issues left before the 1.0 release. We are following semantic versioning, so after the 1.0 release, we won’t change or remove commands or arguments until 2.0.

Here is the list of feature requests that we and the community have submitted. We would value any additions you have, and it also helps us prioritize if you give the things you want a 👍 emoji upvote! We also welcome contributions—if you’re interested in improving the CLI, comment on the relevant issue with your plans for (or questions about) a PR. Another improvement we’re discussing is being able to use our Cloud CLI commands in the main CLI so that you can do commands like temporal cloud namespace create.