Quarkus Temporal

A Quarkus extension that lets you utilize Temporal, orchestrating both mission-critical and mainstream workloads.

Installation

If you want to use this extension, you need to add the io.quarkiverse.temporal:quarkus-temporal extension first to your build file.

For instance, with Maven, add the following dependency to your POM file:

<dependency>
    <groupId>io.quarkiverse.temporal</groupId>
    <artifactId>quarkus-temporal</artifactId>
    <version>0.0.14</version>
</dependency>

Getting Started

Activities and workflows are automatically detected. Simply implement an interface annotated with @ActivityInterface or @WorkflowInterface.

Create a Workflow

@WorkflowInterface
public interface SendEmailWorkflow {

    @WorkflowMethod
    public void run(WorkflowData data);

    @QueryMethod
    public EmailDetails details();
}

The following workflow definition will be automatically bound to the default worker:

public class SendEmailWorkflowImpl implements SendEmailWorkflow {
    @Override
    public void run(WorkflowData data) {
    }
}

It is possible to associate the workflow with one or more named workers instead by annotating it with @TemporalWorkflow:

@TemporalWorkflow(workers = "named-worker")
public class SendEmailWorkflowImpl implements SendEmailWorkflow {
    @Override
    public void run(WorkflowData data) {
    }
}

If you don’t have control over the workflow class, it is also possible to bind it with a worker using the workflow-classes configuration property of the worker.

quarkus.temporal.worker.namedWorker.workflow-classes[0]=io.quarkiverse.temporal.SendEmailWorkflowImpl

In this case, it will not be associated with the default worker unless you also bind it explicitely:

quarkus.temporal.worker.workflow-classes[0]=io.quarkiverse.temporal.SendEmailWorkflowImpl

Each worker can have at most one implementation of a given workflow, but a workflow can have implementations across multiple workers.

Workflows are not provided as CDI beans because dependency injection into workflow instances is strongly discouraged. Injecting dependencies into workflow instances can lead to changes that are incompatible with persisted histories, resulting in NonDeterministicException errors. To provide external configuration to a workflow in a deterministic way, use a Local Activity that returns the configuration to the workflow. Dependency injection into activity instances is allowed, ensuring that the configuration is persisted into the history and remains consistent during replay.

If your project only contains the workflow interfaces, but does not contain the actual workflow implementations, the plugin will assume that the workflow is bound to the default worker. If this is not the case, you can hint quarkus about which workers this workflow is bound to by annotating the interface with @TemporalWorkflow directly.

@WorkflowInterface
@TemporalWorkflow(workers = "named-worker")
public interface SendEmailWorkflow {

    @WorkflowMethod
    public void run(WorkflowData data);

    @QueryMethod
    public EmailDetails details();
}

Create an Activity

@ActivityInterface
public interface SendEmailActivities {
    @ActivityMethod
    public String sendEmail(EmailDetails details);
}

The following activity definition will be added automatically to the default worker:

public class SendEmailActivitiesImpl implements SendEmailActivities {

    @Inject (1)
    Mailer mailer;

    @Override
    public String sendEmail(EmailDetails details) {

    }
}
1 CDI Dependency Injection is allowed in activity definition.

It is possible to associate the activity with one or more named workers instead by annotating it with @TemporalActivity:

@TemporalActivity(workers = "named-worker")
public class SendEmailActivitiesImpl implements SendEmailActivities {
    @Override
    public String sendEmail(EmailDetails details) {

    }
}

If you don’t have control over the activity class, it is also possible to bind it with a worker using the activity-classes configuration property of the worker:

quarkus.temporal.worker.namedWorker.activity-classes[0]=io.quarkiverse.temporal.SendEmailActivitiesImpl

In this case, it will not be associated with the default worker unless you also bind it explicitely:

quarkus.temporal.worker.activity-classes[0]=io.quarkiverse.temporal.SendEmailActivitiesImpl

Similarly, each worker can have at most one implementation of a given activity, but an activity can have implementations across multiple workers.

Using the client

public class MyService {

    @Inject
    WorkflowClient client; (1)

    public void startSubscription(WorkflowData data) {

        WorkflowOptions options = WorkflowOptions.newBuilder()
                .setWorkflowId(data.getEmail())
                .setTaskQueue("<default>") (2)
                .build();

        SendEmailWorkflow workflow = client.newWorkflowStub(SendEmailWorkflow.class, options);
        WorkflowClient.start(workflow::run,data);

    }

}
1 The client can be injected as a CDI bean
2 The default worker queue is <default>. for named worker, use the name of the worker

Stub Injection

It is also possible to inject a workflow stub directly using the TemporalWorkflowStub qualifier:

public class MyService {

    @Inject
    @TemporalWorkflowStub(workflowId = "send-email")
    SendEmailWorkflow workflow;

    public void startSubscription(WorkflowData data) {
        workflow.run(data);
    }

}

If the workflow is bound to multiple workers, the worker parameter is required:

public class MyService {

    @Inject
    @TemporalWorkflowStub(worker = "<default>", workflowId = "send-email")
    SendEmailWorkflow workflow;

    public void startSubscription(WorkflowData data) {
        workflow.run(data);
    }

}

The workflowId can be set at runtime by injecting a TemporalInstance:

public class MyService {

    @Inject
    @TemporalWorkflowStub
    TemporalInstance<SimpleWorkflow> instance;

    public void startSubscription(WorkflowData data) {
        SendEmailWorkflow workflow = instance.workflowId("the-workflow-id");
        workflow.run(data);
    }

}

OpenTelemetry

To wire up Temporal to forward traces and spans to Quarkus OpenTelemetry simply add the OpenTelemetry extension to your application.

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-opentelemetry</artifactId>
</dependency>

This will enable it by default you can disable it with:

quarkus.temporal.telemetry.enabled=false
quarkus.otel.instrument.grpc=false
quarkus.otel.instrument.vertx-http=false

Micrometer Metrics

To wire up Temporal to forward Micrometer metrics to Quarkus OpenTelemetry simply add the Micrometer extension to your application.

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-micrometer-registry-prometheus</artifactId>
</dependency>

This will enable it by default you can disable it with:

quarkus.temporal.metrics.enabled=false

Context Propagation

You can use an MDC (Mapped Diagnostic Context) Propagator to propagate information from the workflow client to workflow execution, workflow to activity, workflow to child workflow, and workflow to child thread created using Async.

To enable the MDC propagator or any custom propagators simply produce a CDI bean implementing the ContextPropagator interface.

package om.yourcompany;

import java.util.HashMap;
import java.util.Map;

import jakarta.inject.Singleton;

import org.apache.commons.lang3.StringUtils;
import org.jboss.logging.Logger;
import org.slf4j.MDC;

import com.google.protobuf.ByteString;

import io.quarkus.arc.Unremovable;
import io.temporal.api.common.v1.Payload;
import io.temporal.common.context.ContextPropagator;
import io.temporal.common.converter.GlobalDataConverter;

/**
 * A {@link ContextPropagator} implementation that propagates the SLF4J MDC
 * (Mapped Diagnostic Context) across Temporal workflow and activity boundaries.
 * This class ensures that MDC entries with keys starting with "X-" are
 * propagated.
 */
@Singleton
@Unremovable
public class MDCContextPropagator implements ContextPropagator {

    private static final Logger LOG = Logger.getLogger(MDCContextPropagator.class);

    /**
     * Gets the name of the context propagator.
     *
     * @return the name of the context propagator, which is the fully qualified
     *         class name.
     */
    @Override
    public String getName() {
        return this.getClass().getName();
    }

    /**
     * Retrieves the current MDC context to be propagated.
     *
     * @return a map containing the current MDC context, filtered to include only
     *         entries with keys starting with "X-".
     */
    @Override
    public Object getCurrentContext() {
        Map<String, String> context = new HashMap<>();
        Map<String, String> mdcContext = MDC.getCopyOfContextMap();
        if (mdcContext != null) {
            mdcContext.entrySet().stream()
                    .filter(entry -> entry.getKey().startsWith("X-"))
                    .forEach(entry -> context.put(entry.getKey(), entry.getValue()));
        }
        return context;
    }

    /**
     * Sets the current MDC context from the given context map.
     *
     * @param context the context map containing MDC entries to be set.
     */
    @Override
    public void setCurrentContext(Object context) {
        if (context instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, String> contextMap = (Map<String, String>) context;
            contextMap.forEach(MDC::put);
        }
    }

    /**
     * Serializes the given context map to a map of Payloads.
     *
     * @param context the context map containing MDC entries to be serialized.
     * @return a map of Payloads representing the serialized context.
     */
    @Override
    public Map<String, Payload> serializeContext(Object context) {
        if (!(context instanceof Map)) {
            return new HashMap<>();
        }
        @SuppressWarnings("unchecked")
        Map<String, String> contextMap = (Map<String, String>) context;
        Map<String, Payload> serializedContext = new HashMap<>();
        contextMap.forEach((key, value) -> GlobalDataConverter.get().toPayload(value)
                .ifPresent(payload -> serializedContext.put(key, payload)));
        return serializedContext;
    }

    /**
     * Deserializes the given map of Payloads to a context map.
     *
     * @param context the map of Payloads to be deserialized.
     * @return a context map containing the deserialized MDC entries.
     */
    public Object deserializeContext(Map<String, Payload> context) {
        Map<String, String> contextMap = new HashMap<>();
        context.forEach((key, payload) -> {

            // Handle empty {} when the data value is empty
            // Adding opentracing seems to add a new value with empty data
            // and the dataconverter throws an error
            // This actually might be a configuration error from earlier
            // but leaving in right now
            //
            // {_tracer-data=metadata {
            // key: "encoding"
            // value: "json/plain"
            // }
            // data: "{}"
            // }
            try {
                String payloadValue = StringUtils.EMPTY; // default value

                // Convert data to string to compare
                ByteString data = payload.getData();

                // Check the value to see if it "empty"
                if (data != null && !data.isEmpty()) {

                    // Check if the value isn't {}'s
                    if (!StringUtils.equals("{}", data.toStringUtf8())) {
                        payloadValue = GlobalDataConverter.get().fromPayload(payload, String.class, String.class);
                    }
                }

                // Add the value into the map
                contextMap.put(key, payloadValue);
            } catch (Exception e) {
                LOG.warnf("Couldn't parse MDC Context Data Key %s", key);
            }
        });
        return contextMap;
    }
}

Interceptors

Interceptors are a mechanism for modifying inbound and outbound SDK calls. Interceptors are commonly used to add tracing and authorization to the scheduling and execution of Workflows and Activities. You can compare these to "middleware" in other frameworks.

To enable interceptors simply produce a CDI bean implementing the WorkflowClientInterceptor interface or WorkerInterceptor interface. Interceptors can be ordered by declaring a @Priority on each interceptor, so they are executed in that order.

package com.yourcompany;

import java.util.Optional;

import jakarta.annotation.Priority;
import jakarta.inject.Singleton;

import io.quarkus.arc.Unremovable;
import io.temporal.api.common.v1.WorkflowExecution;
import io.temporal.client.ActivityCompletionClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.client.WorkflowStub;
import io.temporal.common.interceptors.WorkflowClientCallsInterceptor;
import io.temporal.common.interceptors.WorkflowClientInterceptor;

@Singleton
@Unremovable
@Priority(1)
public class TestWorkflowClientInterceptor implements WorkflowClientInterceptor {
    @Override
    public WorkflowStub newUntypedWorkflowStub(String workflowType, WorkflowOptions options, WorkflowStub next) {
        return next;
    }

    @Override
    public WorkflowStub newUntypedWorkflowStub(WorkflowExecution execution, Optional<String> workflowType, WorkflowStub next) {
        return next;
    }

    @Override
    public ActivityCompletionClient newActivityCompletionClient(ActivityCompletionClient next) {
        return next;
    }

    @Override
    public WorkflowClientCallsInterceptor workflowClientCallsInterceptor(WorkflowClientCallsInterceptor next) {
        return next;
    }
}

Temporal Cloud

You may be using the Temporal Cloud offering instead of self-hosting. Temporal Cloud supports both TLS and API key authentication.

TLS Authentication

You must provide your own CA certificates. These certificates are needed to create a Namespace, which are in turn used to grant Temporal Clients and Workers access to it. You will need:

  • The full Namespace ID from the Cloud Namespace details page such as <namespace>.<account>

  • The gRPC endpoint from the Cloud Namespace details page such as <namespace>.<account>.tmprl.cloud:7233

  • Your mTLS private key

  • Your mTLS x509 Certificate

To configure with Quarkus Temporal TLS:

quarkus.temporal.namespace=your-namespace.123def
quarkus.temporal.connection.target=your-namespace.123def.tmprl.cloud:7233
quarkus.temporal.connection.mtls.client-cert-path=/your-temporal-x509.cert
quarkus.temporal.connection.mtls.client-key-path=/your-temporal.key
quarkus.temporal.connection.mtls.password=Passw0rd

API Key Authentication

Each Temporal Cloud API key is a unique identity linked to role-based access control (RBAC) settings to ensure secure and appropriate access.

You will need:

  • The full Namespace ID from the Cloud Namespace details page such as <namespace>.<account>

  • The gRPC endpoint from the Cloud Namespace details page such as <region>.<cloud_provider>.api.temporal.io:7233.

  • Your API key

To configure with Quarkus Temporal API key:

quarkus.temporal.namespace=<namespace>.<account>
quarkus.temporal.connection.target=<region>.<cloud_provider>.api.temporal.io:7233
quarkus.temporal.connection.api-key=<api-key>

Extension Configuration Reference

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

enable mock for testing

Environment variable: QUARKUS_TEMPORAL_ENABLE_MOCK

boolean

false

either use a channel managed by temporal client (built-in) or use a channel managed by quarkus (quarkus-managed). In this case the channel can be configured using quarkus.grpc.clients.temporal-client.

Environment variable: QUARKUS_TEMPORAL_CHANNEL_TYPE

ChannelType

built-in

If Temporal registers in the health check by pinging the service.

Environment variable: QUARKUS_TEMPORAL_HEALTH_ENABLED

boolean

true

Enable OpenTelemetry instrumentation, enabled by default if OpenTelemetry capability is detected.

Environment variable: QUARKUS_TEMPORAL_TELEMETRY_ENABLED

boolean

true

enable mock for testing

Environment variable: QUARKUS_TEMPORAL_START_WORKERS

boolean

true

A Namespace is a unit of isolation within the Temporal Platform.

Environment variable: QUARKUS_TEMPORAL_NAMESPACE

string

default

Override human-readable identity of the worker. Identity is used to identify a worker and is recorded in the workflow history events. For example when a worker gets an activity task the correspondent ActivityTaskStarted event contains the worker identity as a field. Default is whatever (ManagementFactory. getRuntimeMXBean().getName() returns.

Environment variable: QUARKUS_TEMPORAL_IDENTITY

string

Enable Micrometer, enabled by default if Micrometer capability is detected.

Environment variable: QUARKUS_TEMPORAL_METRICS_ENABLED

boolean

true

The interval at which we report metrics to the metric registry. Default is 15 seconds.

Environment variable: QUARKUS_TEMPORAL_METRICS_REPORT_DURATION

Duration

15S

quarkus.temporal.worker."worker-name".build-id

Assigns a unique identifier to this worker. The identifier must remain consistent with the code the worker utilizes for workflows, activities, and interceptors. For further details, refer to: Temporal Build ID. A Build ID is required if useBuildIdForVersioning is set to true. By default, the latest Git commit ID is used.

Environment variable: QUARKUS_TEMPORAL_WORKER_BUILD_ID

string

quarkus.temporal.worker."worker-name".workflow-classes

Explicitly bind a workflow with this worker

Environment variable: QUARKUS_TEMPORAL_WORKER_WORKFLOW_CLASSES

list of string

quarkus.temporal.worker."worker-name".activity-classes

Explicitly bind a workflow with this worker

Environment variable: QUARKUS_TEMPORAL_WORKER_ACTIVITY_CLASSES

list of string

quarkus.temporal.worker."worker-name".task-queue

Task queue name worker uses to poll. It uses this name for both workflow and activity task queue polls. Default is worker name

Environment variable: QUARKUS_TEMPORAL_WORKER_TASK_QUEUE

string

quarkus.temporal.worker."worker-name".max-worker-activities-per-second

Maximum number of activities started per second by this worker. Default is 0 which means unlimited.

Environment variable: QUARKUS_TEMPORAL_WORKER_MAX_WORKER_ACTIVITIES_PER_SECOND

double

0

quarkus.temporal.worker."worker-name".max-concurrent-activity-execution-size

Maximum number of activities executed in parallel. Default is 200, which is chosen if set to zero.

Environment variable: QUARKUS_TEMPORAL_WORKER_MAX_CONCURRENT_ACTIVITY_EXECUTION_SIZE

int

200

quarkus.temporal.worker."worker-name".max-concurrent-workflow-task-execution-size

Maximum number of simultaneously executed workflow tasks. Default is 200, which is chosen if set to zero.

Environment variable: QUARKUS_TEMPORAL_WORKER_MAX_CONCURRENT_WORKFLOW_TASK_EXECUTION_SIZE

int

200

quarkus.temporal.worker."worker-name".max-concurrent-local-activity-execution-size

Maximum number of local activities executed in parallel. Default is 200, which is chosen if set to zero.

Environment variable: QUARKUS_TEMPORAL_WORKER_MAX_CONCURRENT_LOCAL_ACTIVITY_EXECUTION_SIZE

int

200

quarkus.temporal.worker."worker-name".max-task-queue-activities-per-second

Sets the rate limiting on number of activities that can be executed per second. This is managed by the server and controls activities per second for the entire task queue across all the workers. Notice that the number is represented in double, so that you can set it to less than 1 if needed. For example, set the number to 0.1 means you want your activity to be executed once every 10 seconds. This can be used to protect down stream services from flooding. The zero value of these uses the default value. Default is unlimited.

Environment variable: QUARKUS_TEMPORAL_WORKER_MAX_TASK_QUEUE_ACTIVITIES_PER_SECOND

double

0

quarkus.temporal.worker."worker-name".max-concurrent-workflow-task-pollers

Sets the maximum number of simultaneous long poll requests to the Temporal Server to retrieve workflow tasks. Changing this value will affect the rate at which the worker is able to consume tasks from a task queue. Due to internal logic where pollers alternate between sticky and non-sticky queues, this value cannot be 1 and will be adjusted to 2 if set to that value. Default is 5, which is chosen if set to zero.

Environment variable: QUARKUS_TEMPORAL_WORKER_MAX_CONCURRENT_WORKFLOW_TASK_POLLERS

int

5

quarkus.temporal.worker."worker-name".max-concurrent-activity-task-pollers

Number of simultaneous poll requests on activity task queue. Consider incrementing if the worker is not throttled due to MaxActivitiesPerSecond or MaxConcurrentActivityExecutionSize options and still cannot keep up with the request rate. Default is 5, which is chosen if set to zero.

Environment variable: QUARKUS_TEMPORAL_WORKER_MAX_CONCURRENT_ACTIVITY_TASK_POLLERS

int

5

quarkus.temporal.worker."worker-name".local-activity-worker-only

If set to true worker would only handle workflow tasks and local activities. Non-local activities will not be executed by this worker. Default is false.

Environment variable: QUARKUS_TEMPORAL_WORKER_LOCAL_ACTIVITY_WORKER_ONLY

boolean

false

quarkus.temporal.worker."worker-name".default-deadlock-detection-timeout

Time period in ms that will be used to detect workflows deadlock. Default is 1000ms, which is chosen if set to zero. Specifies an amount of time in milliseconds that workflow tasks are allowed to execute without interruption. If workflow task runs longer than specified interval without yielding (like calling an Activity), it will fail automatically.

Environment variable: QUARKUS_TEMPORAL_WORKER_DEFAULT_DEADLOCK_DETECTION_TIMEOUT

long

1000

quarkus.temporal.worker."worker-name".max-heartbeat-throttle-interval

The maximum amount of time between sending each pending heartbeat to the server. Regardless of heartbeat timeout, no pending heartbeat will wait longer than this amount of time to send. Default is 60s, which is chosen if set to null or 0.

Environment variable: QUARKUS_TEMPORAL_WORKER_MAX_HEARTBEAT_THROTTLE_INTERVAL

Duration

60S

quarkus.temporal.worker."worker-name".default-heartbeat-throttle-interval

The default amount of time between sending each pending heartbeat to the server. This is used if the ActivityOptions do not provide a HeartbeatTimeout. Otherwise, the interval becomes a value a bit smaller than the given HeartbeatTimeout. Default is 30s, which is chosen if set to null or 0.

Environment variable: QUARKUS_TEMPORAL_WORKER_DEFAULT_HEARTBEAT_THROTTLE_INTERVAL

Duration

30S

quarkus.temporal.worker."worker-name".sticky-queue-schedule-to-start-timeout

Timeout for a workflow task routed to the "sticky worker" - host that has the workflow instance cached in memory. Once it times out, then it can be picked up by any worker. Default value is 5 seconds.

Environment variable: QUARKUS_TEMPORAL_WORKER_STICKY_QUEUE_SCHEDULE_TO_START_TIMEOUT

Duration

5S

quarkus.temporal.worker."worker-name".disable-eager-execution

Disable eager activities. If set to true, eager execution will not be requested for activities requested from workflows bound to this Worker. Eager activity execution means the server returns requested eager activities directly from the workflow task back to this worker which is faster than non-eager which may be dispatched to a separate worker. Defaults to false, meaning that eager activity execution is permitted

Environment variable: QUARKUS_TEMPORAL_WORKER_DISABLE_EAGER_EXECUTION

boolean

false

quarkus.temporal.worker."worker-name".use-build-id-for-versioning

Opts the worker in to the Build-ID-based versioning feature. This ensures that the worker will only receive tasks which it is compatible with. For more information see: TODO: Doc link Defaults to false

Environment variable: QUARKUS_TEMPORAL_WORKER_USE_BUILD_ID_FOR_VERSIONING

boolean

false

quarkus.temporal.worker."worker-name".sticky-task-queue-drain-timeout

During graceful shutdown, as when calling WorkerFactory. shutdown(), if the workflow cache is enabled, this timeout controls how long to wait for the sticky task queue to drain before shutting down the worker. If set the worker will stop making new poll requests on the normal task queue, but will continue to poll the sticky task queue until the timeout is reached. This value should always be greater than clients rpc long poll timeout, which can be set via WorkflowServiceStubsOptions. Builder. setRpcLongPollTimeout(Duration). Default is not to wait.

Environment variable: QUARKUS_TEMPORAL_WORKER_STICKY_TASK_QUEUE_DRAIN_TIMEOUT

Duration

0S

quarkus.temporal.worker."worker-name".identity

Override identity of the worker primary specified in a WorkflowClient options.

Environment variable: QUARKUS_TEMPORAL_WORKER_IDENTITY

string

quarkus.temporal.workflow."group-name".workflow-id-reuse-policy

Specifies server behavior if a completed workflow with the same id exists. Note that under no conditions Temporal allows two workflows with the same namespace and workflow id run simultaneously. See @line setWorkflowIdConflictPolicy for handling a workflow id duplication with a Running workflow. Default value if not set: AllowDuplicate

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_WORKFLOW_ID_REUSE_POLICY

TemporalWorkflowIdReusePolicy

allow-duplicate

quarkus.temporal.workflow."group-name".workflow-id-conflict-policy

Specifies server behavior if a Running workflow with the same id exists. See setWorkflowIdReusePolicy for handling a workflow id duplication with a Closed workflow. Cannot be set when workflow-id-reuse-policy is WorkflowIdReusePolicy. Default value if not set: Fail

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_WORKFLOW_ID_CONFLICT_POLICY

TemporalWorkflowIdConflictPolicy

fail

quarkus.temporal.workflow."group-name".workflow-run-timeout

The time after which a workflow run is automatically terminated by Temporal service with WORKFLOW_EXECUTION_TIMED_OUT status. The default is set to the same value as the Workflow Execution Timeout.

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_WORKFLOW_RUN_TIMEOUT

Duration

quarkus.temporal.workflow."group-name".workflow-execution-timeout

The time after which workflow execution (which includes run retries and continue as new) is automatically terminated by Temporal service with WORKFLOW_EXECUTION_TIMED_OUT status. The default value is ∞ (infinite) - [TO DO]: check with temporal how to set this infinite value

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_WORKFLOW_EXECUTION_TIMEOUT

Duration

quarkus.temporal.workflow."group-name".workflow-task-timeout

Maximum execution time of a single Workflow Task. In the majority of cases there is no need to change this timeout. Note that this timeout is not related to the overall Workflow duration in any way. It defines for how long the Workflow can get blocked in the case of a Workflow Worker crash. The default value is 10 seconds. Maximum value allowed by the Temporal Server is 1 minute.

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_WORKFLOW_TASK_TIMEOUT

Duration

10S

quarkus.temporal.workflow."group-name".cron-schedule

cron schedule

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_CRON_SCHEDULE

string

quarkus.temporal.workflow."group-name".disable-eager-execution

If WorkflowClient is used to create a WorkerFactory that is started has a non-paused worker on the right task queue has available workflow task executor slots and such a WorkflowClient is used to start a workflow, then the first workflow task could be dispatched on this local worker with the response to the start call if Server supports it. This option can be used to disable this mechanism. Default is true

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_DISABLE_EAGER_EXECUTION

boolean

true

quarkus.temporal.workflow."group-name".start-delay

Time to wait before dispatching the first workflow task. If the workflow gets a signal before the delay, a workflow task will be dispatched and the rest of the delay will be ignored. A signal from signal with start will not trigger a workflow task. Cannot be set the same time as a CronSchedule.

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_START_DELAY

Duration

Connection to the temporal server

Type

Default

Sets a target string, which can be either a valid NameResolver-compliant URI, or an authority string. See ManagedChannelBuilder#forTarget(String) for more information about parameter format. Default is 127.0.0.1:7233

Environment variable: QUARKUS_TEMPORAL_CONNECTION_TARGET

string

127.0.0.1:7233

Sets option to enable SSL/ TLS/ HTTPS for gRPC.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_ENABLE_HTTPS

boolean

false

Temporal Cloud API key is a unique identity linked to role-based access control (RBAC) settings to ensure secure and appropriate access.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_API_KEY

string

Interval of the first retry, on regular failures. If coefficient is 1.0 then it is used for all retries. Defaults to 100ms.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_RPC_RETRY_INITIAL_INTERVAL

Duration

100MS

Interval of the first retry, on congestion related failures (i. e. RESOURCE_EXHAUSTED errors). If coefficient is 1.0 then it is used for all retries. Defaults to 1000ms.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_RPC_RETRY_CONGESTION_INITIAL_INTERVAL

Duration

1000MS

Maximum time to retry. When exceeded the retries stop even if maximum retries is not reached yet. Defaults to 1 minute.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_RPC_RETRY_EXPIRATION

Duration

1M

Coefficient used to calculate the next retry interval. The next retry interval is previous interval multiplied by this coefficient. Must be 1 or larger. Default is 1.5.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_RPC_RETRY_BACKOFF_COEFFICIENT

double

1.5

When exceeded the amount of attempts, stop. Even if expiration time is not reached. Default is unlimited which is chosen if set to 0.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_RPC_RETRY_MAXIMUM_ATTEMPTS

int

0

Maximum interval between retries. Exponential backoff leads to interval increase. This value is the cap of the increase. Default is 50x of initial interval. Can’t be less than initial-interval

Environment variable: QUARKUS_TEMPORAL_CONNECTION_RPC_RETRY_MAXIMUM_INTERVAL

Duration

Maximum amount of jitter to apply. 0.2 means that actual retry time can be +/- 20% of the calculated time. Set to 0 to disable jitter. Must be lower than 1. Default is 0.2.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_RPC_RETRY_MAXIMUM_JITTER_COEFFICIENT

double

0.2

Makes request that receives a server response with gRPC code and failure of detailsClass type non-retryable.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_RPC_RETRY_DO_NOT_RETRY

list of Code

Path to the client certificate.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_MTLS_CLIENT_CERT_PATH

path

Path to the client key.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_MTLS_CLIENT_KEY_PATH

path

Password for the client key.

Environment variable: QUARKUS_TEMPORAL_CONNECTION_MTLS_PASSWORD

string

Retry options

Type

Default

quarkus.temporal.workflow."group-name".retries.do-not-retry

List of application failures types to not retry

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_RETRIES_DO_NOT_RETRY

list of string

[]

quarkus.temporal.workflow."group-name".retries.initial-interval

Interval of the first retry. If coefficient is 1.0 then it is used for all retries. Default is 1 second.

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_RETRIES_INITIAL_INTERVAL

Duration

1S

quarkus.temporal.workflow."group-name".retries.backoff-coefficient

Coefficient used to calculate the next retry interval. The next retry interval is previous interval multiplied by this coefficient. Must be 1 or larger. Default is 2.0.

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_RETRIES_BACKOFF_COEFFICIENT

double

2.0

quarkus.temporal.workflow."group-name".retries.set-maximum-attempts

When exceeded the amount of attempts, stop. Even if expiration time is not reached. Default is unlimited if set to 0.

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_RETRIES_SET_MAXIMUM_ATTEMPTS

int

0

quarkus.temporal.workflow."group-name".retries.maximum-interval

Maximum interval between retries. Exponential backoff leads to interval increase. This value is the cap of the increase. Default is 100x of initial interval. Can’t be less than initialInterval

Environment variable: QUARKUS_TEMPORAL_WORKFLOW_RETRIES_MAXIMUM_INTERVAL

Duration

About the Duration format

To write duration values, use the standard java.time.Duration format. See the Duration#parse() Java API documentation for more information.

You can also use a simplified format, starting with a number:

  • If the value is only a number, it represents time in seconds.

  • If the value is a number followed by ms, it represents time in milliseconds.

In other cases, the simplified format is translated to the java.time.Duration format for parsing:

  • If the value is a number followed by h, m, or s, it is prefixed with PT.

  • If the value is a number followed by d, it is prefixed with P.