Using Temporal

4/27/2023

Using the Temporal CLI

Loren

Loren Sands-Ramshaw

Developer Relations Engineer

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.