Set Cron Schedule in WorkflowOptions
To set a Cron Schedule in Java, use setCronSchedule() method on WorkflowOptions.Builder. The Cron Schedule is provided as a String option when spawning a Workflow Execution. Setting setCronSchedule changes the Workflow Execution into a Temporal Cron Job. The default timezone for a Cron is UTC. Type: String, Default: None. Example: YourWorkflowInterface workflow1 = YourWorker.yourclient.newWorkflowStub(YourWorkflowInterface.class, WorkflowOptions.newBuilder().setWorkflowId("YourWF").setTaskQueue(YourWorker.TASK_QUEUE).setCronSchedule("* * * * *").build());
Trigger a Schedule in Java
To trigger a Scheduled Workflow Execution in Java, use the trigger() method on the ScheduleHandle. By default, this action is subject to the Overlap Policy of the Schedule. This is helpful when you want to execute a Workflow outside of its scheduled time. Example: ScheduleHandle handle = client.getHandle("schedule-id"); handle.trigger();
Pause a Schedule in Java
To pause a Scheduled Workflow Execution in Java, use the pause() method on the ScheduleHandle. When you pause a Schedule, all future Workflow Runs associated with the Schedule are temporarily stopped. You can pass a note to the pause() method to provide a reason for pausing the schedule. Example: ScheduleHandle handle = client.getHandle("schedule-id"); handle.pause("Pausing the schedule for now");
List all Schedules in Java
To list all schedules, use the listSchedules() asynchronous method on the ScheduleClient. If a schedule is added or deleted, it may not be available in the list immediately. Example: Stream<ScheduleListDescription> scheduleStream = client.listSchedules();
Describe a Schedule in Java
To describe a Scheduled Workflow Execution in Java, use the describe() method on the ScheduleHandle. This action shows the current Schedule configuration, including information about past, current, and future Workflow Runs. Example: ScheduleHandle handle = client.getHandle("schedule-id"); ScheduleDescription description = handle.describe();
Delete a Schedule in Java
To delete a Scheduled Workflow Execution in Java, use the delete() method on the ScheduleHandle. When you delete a Schedule, it does not affect any Workflows that were already started by the Schedule. Example: ScheduleHandle handle = client.getHandle("schedule-id"); handle.delete();
Backfill a Schedule in Java
The backfill action executes Actions ahead of their specified time range, which is useful when you need to execute a missed or delayed Action, or when you want to test the Workflow before its scheduled time. Use the backfill() method on the ScheduleHandle. Example: ScheduleHandle handle = client.getHandle("schedule-id"); Instant now = Instant.now(); handle.backfill(Arrays.asList(new ScheduleBackfill(now.minusMillis(5500), now.minusMillis(2500)), new ScheduleBackfill(now.minusMillis(2500), now)));
Create a Schedule with ScheduleClient
To create a Scheduled Workflow Execution in Java, use the createSchedule() method on the ScheduleClient. When creating the ScheduleClient, you can set a custom Namespace using ScheduleClientOptions. Schedules must be initialized with a Schedule ID. The Schedule is configured using Schedule.newBuilder() with an action (ScheduleActionStartWorkflow) and a spec (ScheduleSpec). Example: ScheduleClient scheduleClient = ScheduleClient.newInstance(service, ScheduleClientOptions.newBuilder().setNamespace("custom_namespace").build()); ScheduleHandle handle = scheduleClient.createSchedule("ScheduleId", schedule, ScheduleOptions.newBuilder().build());
Workflow.sideEffect() method signature and usage
To use a Side Effect in Java, call the Workflow.sideEffect() function in your Workflow Execution and return the non-deterministic code. The method takes a Class parameter for the return type and a Function that supplies the non-deterministic value.
Example: generating random integer with sideEffect()
int random = Workflow.sideEffect(Integer.class, () -> random.nextInt(100));
Example: side effect with random number and environment variable
int randomInt = Workflow.sideEffect( int.class, () -> {
Random random = new SecureRandom();
return random.nextInt();
});
String userHome = Workflow.sideEffect(String.class, () -> System.getenv("USER_HOME"));
Workflow.newRandom() for deterministic random numbers
Java provides a deterministic method to generate random numbers. Use Workflow.newRandom() to generate random numbers deterministically within a workflow without needing a Side Effect.
Example: generating random integer deterministically
int randomInt = Workflow.newRandom().nextInt();
Workflow.randomUUID() for deterministic UUID generation
Java provides a deterministic method to generate random UUIDs. Use Workflow.randomUUID() to generate a random UUID deterministically within a workflow without needing a Side Effect.
Example: generating random UUID deterministically
String randomUUID = Workflow.randomUUID().toString();
Workflow Retry Policy Java example
This example shows how to set a Workflow Retry Policy using WorkflowOptions.Builder.setRetryOptions(RetryOptions.newBuilder().build()):
GreetWorkflowInterface workflow1 =
WorkerGreet.greetclient.newWorkflowStub(
GreetWorkflowInterface.class,
WorkflowOptions.newBuilder()
.setWorkflowId("GreetWF")
.setTaskQueue(WorkerGreet.TASK_QUEUE)
.setRetryOptions(RetryOptions.newBuilder()
.build()));
Setting Workflow timeouts in Java
Workflow timeouts are set when starting the Workflow Execution using WorkflowOptions.Builder methods in client code. The available methods are: setWorkflowExecutionTimeout(Duration), setWorkflowRunTimeout(Duration), and setWorkflowTaskTimeout(Duration).
Workflow Retry Policy should be used cautiously
Retry Policies should be used with Workflow Executions only in certain situations.
Workflow Retry Policy default behavior
Workflow Executions do not retry by default. The RetryOptions type defaults to null, which means no retries will be attempted.
Workflow timeouts Java example
This example shows how to set Workflow timeouts using WorkflowOptions.Builder in Java:
YourWorkflowInterface workflow1 =
WorkerGreet.greetclient.newWorkflowStub(
GreetWorkflowInterface.class,
WorkflowOptions.newBuilder()
.setWorkflowId("YourWorkflow")
.setTaskQueue(WorkerGreet.TASK_QUEUE)
.setWorkflowExecutionTimeout(Duration.ofSeconds(10))
.build());
Java Timer syntax with sleep()
To set a Timer in Java, use Workflow.sleep() and pass the number of seconds you want to wait before continuing.
Timer definition and purpose
A Workflow can set a durable Timer for a fixed time period. Timers are persisted, so even if your Worker or Temporal Service is down when the time period completes, as soon as your Worker and Temporal Service are back up, the Timer resolves and your code continues executing. A Workflow can sleep for months.
Workflow::async for parallel activity and child workflow execution
Use Workflow::async to explicitly wrap code (including yield constructs) to execute nested activities and child workflows in parallel with main Workflow code. Call yield on the Promise returned by Workflow::async to merge the execution result back to the primary Workflow method.
PHP example: Workflow::async for parallel activities
Example of using Workflow::async to run activities in parallel:
```php
public function greet(string $name): \Generator
{
$first = Workflow::async(
function () use ($name) {
$hello = yield $this->greetingActivity->composeGreeting('Hello', $name);
$bye = yield $this->greetingActivity->composeGreeting('Bye', $name);
return $hello . '; ' . $bye;
}
);
$second = Workflow::async(
function () use ($name) {
$hello = yield $this->greetingActivity->composeGreeting('Hola', $name);
$bye = yield $this->greetingActivity->composeGreeting('Chao', $name);
return $hello . '; ' . $bye;
}
);
// blocks until $first and $second complete
return (yield $first) . "\n" . (yield $second);
}
```
This example shows two separate async execution paths running in parallel. Yielding on the async results blocks until both complete, then their results are combined.
Timer summary in PHP workflows
Timers within a workflow can have a summary attached using TimerOptions::new()->withSummary(). The summary provides context for the timer in the UI. Example: yield Workflow::timer(300, TimerOptions::new()->withSummary('Waiting for payment confirmation')).
Starting workflow asynchronously in PHP
Workflows can be started asynchronously using the start() method on the workflow client: $workflowClient->start($workflow, 'workflow input').
Starting workflow with static summary and details in PHP
Example showing how to start a workflow with static summary and details using WorkflowOptions: $workflow = $workflowClient->newWorkflowStub(YourWorkflow::class, WorkflowOptions::new()->withWorkflowId('your-workflow-id')->withTaskQueue('your-task-queue')->withStaticSummary('Order processing for customer #12345')->withStaticDetails('Processing premium order with expedited shipping')). The result is obtained by calling $result = $workflow->yourWorkflowMethod('workflow input').
Workflow class definition in PHP
Define Workflows as PHP classes annotated with the #[WorkflowInterface] attribute. Each Workflow method must be annotated with #[WorkflowMethod].
Create Activity stub in workflow
Inside a Workflow method, create an Activity stub using Workflow::newActivityStub() with the Activity class name and ActivityOptions. Then call methods on the stub using `yield` to execute the Activity asynchronously.
Example Workflow client execution in PHP
A client file example (client.php) that creates a WorkflowClient, creates a Workflow stub, and executes the Workflow: ```php
<?php
declare(strict_types=1);
use Temporal\Client\GRPC\ServiceClient;
use Temporal\Client\WorkflowClient;
ini_set('display_errors', 'stderr');
require "vendor/autoload.php";
$client = new WorkflowClient(
ServiceClient::create('localhost:7233'),
);
$workflowStub = $client->newWorkflowStub(\App\SayHelloWorkflow::class);
$result = $workflowStub->sayHello('Temporal');
echo "Result: {$result}\n";
```
Example Workflow implementation in PHP
A Workflow class example with the Temporal\Workflow\WorkflowInterface attribute and a method annotated with Temporal\Workflow\WorkflowMethod that creates an Activity stub and executes it: ```php
<?php
declare(strict_types=1);
namespace App;
use Temporal\Activity\ActivityOptions;
use Temporal\Workflow;
use Temporal\Workflow\WorkflowInterface;
use Temporal\Workflow\WorkflowMethod;
#[WorkflowInterface]
class SayHelloWorkflow
{
#[WorkflowMethod]
public function sayHello(string $name)
{
$activity = Workflow::newActivityStub(
GreetingActivity::class,
ActivityOptions::new()
->withStartToCloseTimeout(5),
);
return yield $activity->greet($name);
}
}
```
Workflow execution via client
Create a WorkflowClient by passing a ServiceClient created with the Temporal Service address (e.g., 'localhost:7233'). Use $client->newWorkflowStub() to create a stub for the Workflow class, then call the Workflow method to execute it.
PHP SDK Workflow documentation topics
The PHP SDK documentation covers the following workflow topics: Workflow Basics, Child Workflows, Continue-As-New, Cancellation, Timeouts, Message Passing, Schedules, Timers, Side effects, and Versioning.
PHP SDK Continue-As-New function signature and usage
In PHP, call Workflow::continueAsNew() with the Workflow type name and an array of input parameters. This stops the current Workflow immediately and starts a new one. Example: Workflow::continueAsNew(Workflow::getInfo()->type->name, [new ClusterManagerInput($state, $testFlag)]);
Set Cron Schedule in PHP with withCronSchedule
Use withCronSchedule() to set a Cron Schedule when creating a Workflow using WorkflowOptions. Setting withCronSchedule turns the Workflow Execution into a Temporal Cron Job.
Paused Workflow from Schedule remains open
If a Workflow Execution started by a Schedule is Paused, it remains open and can affect future scheduled starts through the Schedule's Overlap Policy.
WorkflowExecutionTimeout vs WorkflowRunTimeout for Cron
When using Cron Schedules in PHP, Execution timeout limits total time and Cron will stop executing after this timeout, while Run timeout limits duration of a single workflow invocation.
Cron Jobs example in PHP
Example of setting a Cron Schedule in PHP:
```php
$workflow = $this->workflowClient->newWorkflowStub(
CronWorkflowInterface::class,
WorkflowOptions::new()
->withWorkflowId(CronWorkflowInterface::WORKFLOW_ID)
->withCronSchedule('* * * * *')
->withWorkflowExecutionTimeout(CarbonInterval::minutes(10))
->withWorkflowRunTimeout(CarbonInterval::minute(1))
);
$run = $this->workflowClient->start($workflow, 'Antony');
```
Temporal Cron Jobs definition
A Temporal Cron Job is a series of Workflow Executions that occur when a Cron Schedule is provided in the call to spawn a Workflow Execution.
Start Delay with WorkflowStartDelay
To delay Workflow execution without regular launches, use the Start Delay functionality by specifying the time to wait before dispatching the first Workflow task with withWorkflowStartDelay().
Start Delay example in PHP
Example of using Start Delay in PHP:
```php
$workflow = $workflowClient->newWorkflowStub(
GreeterWorkflowInterface::class,
WorkflowOptions::new()
->withWorkflowStartDelay(CarbonInterval::minutes(10)),
);
$workflowClient->start($workflow, 'Hello world!');
```
Do not modify workflow state inside Side Effects
You should not modify the Workflow state inside a Side Effect, because they are not re-executed during Replay. Side Effect functions should only return a value, and that value can be used in Workflow code to alter state.
Side Effects must not fail or throw exceptions
Side Effects should not fail. An exception thrown from the Side Effect causes failure and retry of the current Workflow Task.
Side Effects do not re-execute during replay
A Side Effect does not re-execute during a Replay. Instead, it returns the recorded result from the Workflow Execution Event History.
Side Effects execute non-deterministic code in workflows
Side Effects are used to execute non-deterministic code, such as generating a UUID or a random number, without compromising determinism in the Workflow. Results are stored into the Workflow Event History.
Side Effects example with random number generation in PHP
The following example shows how to use Workflow::sideEffect() to generate a random number in a PHP Workflow:
```php
#[Workflow\WorkflowMethod]
public function run()
{
$random = yield Workflow::sideEffect(fn() => random_int(0, 100));
if ($random < 50) {
// ...
} else {
// ...
}
}
```
This example demonstrates using a Side Effect to generate a random integer between 0 and 100 without compromising workflow determinism.
Workflow::sideEffect() function syntax in PHP
To use a Side Effect in PHP, use the Workflow::sideEffect() function in your Workflow Definition to run non-deterministic code and return a value. The function accepts a callable and is used with the yield keyword.
Example: Setting Workflow Execution Timeout in PHP
$workflow = $this->workflowClient->newWorkflowStub(
DynamicSleepWorkflowInterface::class,
WorkflowOptions::new()
->withWorkflowId(DynamicSleepWorkflow::WORKFLOW_ID)
->withWorkflowIdReusePolicy(WorkflowIdReusePolicy::WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE)
->withWorkflowExecutionTimeout(CarbonInterval::minutes(2))
);
This example shows how to create a Workflow stub with a WorkflowOptions instance that sets the Workflow Execution Timeout to 2 minutes using CarbonInterval.
PHP WorkflowOptions timeout configuration methods
In PHP SDK, workflow timeouts are configured using WorkflowOptions instance methods: withWorkflowExecutionTimeout(), withWorkflowRunTimeout(), and withWorkflowTaskTimeout().
Workflow Run Timeout restricts maximum duration of single Workflow Run
Workflow Run Timeout restricts the maximum amount of time that a single Workflow Run can last.
Default Workflow type name in PHP
If the name parameter of a Workflow method attribute is not specified, the short name of the Workflow interface is used as the default Workflow type.
WorkflowMethod attribute in PHP
The #[WorkflowMethod] attribute indicates an entry point to a Workflow. It contains parameters that specify timeouts and a Task Queue name. Required parameters such as executionStartToCloseTimeoutSeconds that are not specified through the attribute must be provided at runtime.
Java plugin example with workflow
Example of registering a workflow in a Java plugin:
@WorkflowInterface
public interface HelloWorkflow {
@WorkflowMethod
String run(String name);
}
public static class HelloWorkflowImpl implements HelloWorkflow {
@Override
public String run(String name) {
return "Hello, " + name + "!";
}
}
SimplePlugin workflowPlugin =
SimplePlugin.newBuilder("organization.PluginName")
.registerWorkflowImplementationTypes(HelloWorkflowImpl.class)
.build();
Python plugin example with workflow
Example of registering a workflow in a Python plugin:
@workflow.defn
class HelloWorkflow:
@workflow.run
async def run(self, name: str) -> str:
return f"Hello, {name}!"
plugin = SimplePlugin("organization.PluginName", workflows=[HelloWorkflow])
Go plugin example with workflow
Example of registering a workflow in a Go plugin:
func HelloWorkflow(ctx workflow.Context, name string) (string, error) {
return "Hello, " + name + "!", nil
}
func createWorkflowPlugin() (*temporal.SimplePlugin, error) {
return temporal.NewSimplePlugin(temporal.SimplePluginOptions{
Name: "organization.PluginName",
RunContextBefore: func(ctx context.Context, options temporal.SimplePluginRunContextBeforeOptions) error {
options.Registry.RegisterWorkflowWithOptions(
HelloWorkflow,
workflow.RegisterOptions{Name: "HelloWorkflow"},
)
return nil
},
})
}
DotNet plugin example with workflow
Example of registering a workflow in a DotNet plugin:
[Workflow]
class SimpleWorkflow
{
[WorkflowRun]
public Task<string> RunAsync(string name) => Task.FromResult($"Hello, {name}!");
}
SimplePlugin workflowPlugin = new SimplePlugin(
"organization.PluginName",
new SimplePluginOptions() { }.AddWorkflow<SimpleWorkflow>());
Ruby plugin example with workflow
Example of registering a workflow in a Ruby plugin:
class HelloWorkflow < Temporalio::Workflow::Definition
def execute(name)
"Hello, #{name}!"
end
end
plugin = Temporalio::SimplePlugin.new(
name: 'organization.PluginName',
workflows: [HelloWorkflow]
)
Fail a Workflow Execution with ApplicationError
To deliberately fail a Workflow Execution, raise an ApplicationError. This puts the Workflow Execution in Failed state with no automatic retries. Use this for permanent failures where retrying won't help, such as business rule violations or invalid input data.
Saga pattern for rollback logic
The Saga pattern coordinates a sequence of operations where each operation has a compensating action to undo its effects. If any operation fails, execute compensating actions in reverse order to roll back previous operations. Use this for multi-step processes like e-commerce checkout, distributed transactions across services, and multi-stage data updates.
Don't use Workflow Retry Policies
Unlike Activities, Workflows don't retry by default and usually shouldn't add a Retry Policy. Workflows are deterministic and not designed for failure-prone operations. A Workflow failure typically indicates a code bug or bad input data—retrying the entire Workflow repeats the same logic without fixing the underlying issue. If you need retry logic for specific Workflow operations, implement it in your Workflow code rather than using a Workflow Retry Policy.