new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Temporal · Develop · all subjects

workflows/message-passing

179 notes in this subject, read out of this brain and free to use. This is page 1 of 3.

Signaling multiple Workflows with base interface

Example of using a base Workflow interface to Signal multiple implementations: ```java Retryable r1 = client.newWorkflowStub(Retryable.class, firstWorkflowId); Retryable r2 = client.newWorkflowStub(Retryable.class, secondWorkflowId); r1.retryNow(); r2.retryNow(); ```

Query handler annotation and constraints

Use the @QueryMethod annotation to define a Query handler in the Workflow interface. Query handlers must not modify Workflow state and cannot perform blocking operations such as executing an Activity. A Query handler must return a value and the query operation retrieves state from a Workflow Execution synchronously.

Dynamic component fallback behavior

When an unregistered or unrecognized Workflow, Activity, or message request arrives with a recognized method signature, the Worker can use a pre-registered dynamic stand-in. For example, if a request arrives to start a Workflow named 'MyUnknownWorkflow' and there's no registered Workflow Definition of that type, the Worker checks for a registered dynamic Workflow and invokes it if the signature matches.

Blocking Update handler example with Activity

The following Update handler makes a blocking call to execute an Activity: @Override public Language setLanguage(Language language) { if (!greetings.containsKey(language)) { String greeting = activity.greetingService(language); if (greeting == null) { throw ApplicationFailure.newFailure("Greeting service does not support: " + language, "GreetingFailure"); } greetings.put(language, greeting); } Language previousLanguage = this.language; this.language = language; return previousLanguage; }

Send Update from client

An Update is a synchronous, blocking call that can change Workflow state, control its flow, and return a result. Call the Update method on a WorkflowStub in Client code and wait for the Update to complete. Example: Language previousLanguage = workflow.setLanguage(Language.CHINESE).

Signal handler annotation and behavior

Use the @SignalMethod annotation to define a Signal handler in the Workflow interface. A Signal is an asynchronous message sent to a running Workflow Execution to change its state and control its flow. Signal handlers must not return a value; the response is sent immediately from the server without waiting for the Workflow to process the Signal. Signal handlers can be blocking, allowing use of Activities, Child Workflows, Workflow.sleep Timers, Workflow.await conditions, and other async operations.

Get Activity type in DynamicActivity

Use Activity.getExecutionContext() to get information about the Activity type that should be implemented dynamically. This provides access to getInfo() which contains the Activity type.

Query handler errors and failures

When working with Queries, errors include: if no Workflow Worker is polling the Task Queue, you receive a WorkflowServiceException with cause StatusRuntimeException and status FAILED_PRECONDITION; if Query fails, you receive a WorkflowQueryException if something goes wrong during Query execution (any exception in a Query handler triggers this); if the handler blocks the thread too long without yielding, it causes Workflow Task failure.

@WorkflowInit example code

The constructor and @WorkflowMethod must have the same parameters. Example: @WorkflowInit public GreetingWorkflowImpl(String input) { this.nameWithTitle = "Sir " + input; this.titleHasBeenChecked = false; } @Override public String getGreeting(String input) { Workflow.await(() -> titleHasBeenChecked); return "Hello " + nameWithTitle; } The handler is now guaranteed to see the workflow input after it has been processed by the constructor.

Wait for message handlers to finish before Workflow completes

When your Workflow uses blocking Signal or Update handlers, your main Workflow method can return or Continue-as-New while a handler is still waiting on an async task. This may interrupt the handler and cause Client errors. Use Workflow.await(() -> Workflow.isEveryHandlerFinished()); in your main Workflow method to wait for all handlers to complete before the Workflow ends.

executeUpdateWithStart WorkflowClient API

Use executeUpdateWithStart to obtain the update result directly. It returns once the update result is available or when the API call times out. The update wait stage on UpdateOptions is optional; when specified, it must be WorkflowUpdateStage.COMPLETED.

WorkflowUpdateHandle methods

You can use a WorkflowUpdateHandle to obtain: getExecution() returns the Workflow Execution that this Update was sent to; getId() returns the Update's unique ID, useful for deduplication when using Continue-As-New; getResultAsync() returns a CompletableFuture which can be used to wait for the Update to complete.

Send Signal from client

To send a Signal from Client code, call a Signal method on the WorkflowStub. Example: workflow.approve(new ApproveInput("Me")). The call returns when the server accepts the Signal; it does not wait for the Signal to be delivered to the Workflow Execution. You can only send Signals to Workflow Executions that have not closed.

Update handler annotation and features

Use the @UpdateMethod annotation to define an Update handler in the Workflow interface. An Update is a trackable synchronous request sent to a running Workflow Execution that can change Workflow state, control its flow, and return a result. The sender must wait until the Worker accepts or rejects the Update, and may wait further to receive a returned value or exception. Update handlers can be blocking and mutate Workflow state.

DynamicWorkflow implementation

Use DynamicWorkflow to implement Workflow Types dynamically. Register a Workflow implementation type that extends DynamicWorkflow to implement any Workflow Type that is not explicitly registered with the Worker. The dynamic Workflow interface is implemented with the execute method which takes EncodedValues that are inputs to the Workflow Execution. Example: public class MyDynamicWorkflow implements DynamicWorkflow { @Override public Object execute(EncodedValues args) { } }

DynamicActivity implementation

Use DynamicActivity to implement any number of Activity types dynamically. When an Activity implementation that extends DynamicActivity is registered, it is called for any Activity type invocation that doesn't have an explicitly registered handler. Implement with the execute method. Example: public static class DynamicGreetingActivityImpl implements DynamicActivity { @Override public Object execute(EncodedValues args) { String activityType = Activity.getExecutionContext().getInfo().getActivityType(); return activityType + ": " + args.get(0, String.class) + " " + args.get(1, String.class) + " from: " + args.get(2, String.class); } }

No Worker polling for Update

When no Workflow Workers are polling the Task Queue for an Update request, the request will be retried by the SDK Client indefinitely. You can impose a timeout with CompletableFuture.get() method with a timeout parameter, which throws java.util.concurrent.TimeoutException when it expires.

getMessage handlers must serialize parameters and return values

The parameters and return values of handlers and the main Workflow function must be serializable.

WorkflowLock concurrent handler example

Correct concurrent handler execution with locks: public class DataWorkflowImpl implements DataWorkflow { WorkflowLock lock = Workflow.newWorkflowLock(); ... @Override public void safeSignalHandler() { try { lock.lock(); Data data = activity.fetchData(); this.x = data.x; Workflow.sleep(Duration.ofSeconds(1)); this.y = data.y; } finally { lock.unlock(); } } }

Use WorkflowLock to prevent concurrent handler execution

Use WorkflowLock to coordinate access and ensure only one handler instance can execute a specific section of code at any given time. Create with WorkflowLock lock = Workflow.newWorkflowLock(); Use try/finally block: lock.lock(); try { /* handler code */ } finally { lock.unlock(); }

@WorkflowInit annotation for constructor parameters

Use the @WorkflowInit annotation on your Workflow constructor to give it the same Workflow parameters as your @WorkflowMethod. The SDK ensures your constructor receives the Workflow input arguments that the Client sent. The Workflow input arguments are also passed to your @WorkflowMethod method. This is useful if message handlers need access to Workflow input. Note: do not make blocking calls from within @WorkflowInit as it could result in incomplete Workflow initialization.

Handler unfinished policy annotation

Use the unfinishedPolicy argument on @SignalMethod or @UpdateMethod annotations to control warnings when allowing a Workflow Execution to finish with unfinished handler executions. Set unfinishedPolicy = HandlerUnfinishedPolicy.ABANDON to silence warnings on a per-handler basis. Example: @UpdateMethod(unfinishedPolicy = HandlerUnfinishedPolicy.ABANDON) void myUpdate();

Update-With-Start example code

With startUpdateWithStart: WorkflowUpdateHandle<Language> handle = WorkflowClient.startUpdateWithStart(workflow::setLanguage, Language.ENGLISH, UpdateOptions.<Language>newBuilder().setWaitForStage(WorkflowUpdateStage.ACCEPTED).build(), new WithStartWorkflowOperation<>(workflow::getGreetings)); Language previousLanguage = handle.getResultAsync().get(); With executeUpdateWithStart: Language previousLanguage = WorkflowClient.executeUpdateWithStart(workflow::setLanguage, Language.ENGLISH, UpdateOptions.<Language>newBuilder().build(), new WithStartWorkflowOperation<>(workflow::getGreetings));

DynamicQueryHandler implementation

Implement Query handlers dynamically using DynamicQueryHandler. Register with Workflow.registerListener(Object). When registered, any Queries sent to the Workflow without a defined handler are delivered to the DynamicQueryHandler. You can only register one Workflow.registerListener per Workflow Execution. Example: Workflow.registerListener((DynamicQueryHandler)(queryName, encodedArgs) -> name = encodedArgs.get(0, String.class));

Update-With-Start requirements

To use Update-with-Start, provide a WorkflowStub created from WorkflowOptions requiring Workflow Id Conflict Policy to be specified (choose 'Use Existing' and use an idempotent Update handler); UpdateOptions with the update wait stage specified (Workflow Id is optional, Run Id cannot be set); and WithStartWorkflowOperation specifying the workflow method (can only be used once).

startUpdateWithStart WorkflowClient API

Use the startUpdateWithStart WorkflowClient API to send an Update-with-Start. It returns once the requested Update wait stage has been reached or when the request times out. Use the WorkflowUpdateHandle to retrieve a result from the Update.

Signal-With-Start example code

Call signalWithStart and pass the name of your Signal with its arguments. Example: WorkflowStub untypedWorkflowStub = client.newUntypedWorkflowStub("GreetingWorkflow", WorkflowOptions.newBuilder().setWorkflowId(workflowId).setTaskQueue(taskQueue).build()); untypedWorkflowStub.signalWithStart("setCustomer", new Object[] {customer2}, new Object[] {customer1}); String greeting = untypedWorkflowStub.getResult(String.class);

Send Signal from another Workflow

A Workflow can send a Signal to another Workflow, known as an External Signal. Use Workflow.newExternalWorkflowStub to create an ExternalWorkflowStub for the other Workflow. Call Signal methods on the external stub to Signal the other Workflow. Example: OtherWorkflow other = Workflow.newExternalWorkflowStub(OtherWorkflow.class, otherWorkflowID); other.mySignalMethod();

Send Query from client

Call a Query method defined within a Workflow from a WorkflowStub created in Client code to send a Query to a Workflow Execution. Example: List<Language> languages = workflow.getLanguages(new GetLanguagesInput(false)). Sending a Query does not add events to a Workflow's Event History.

Update validator annotation and usage

Define an Update validator with the @UpdateValidatorMethod annotation and use the updateName argument to connect it to its Update handler. Update validators are optional and must return void and accept the same argument types as the handler. To reject an Update, throw an exception of any type in the validator. Validators cannot mutate Workflow state. Without a validator, Updates are always accepted.

Prefer class over multiple parameters for handlers

Prefer a single class with multiple fields over using multiple input parameters for message handlers. A class allows you to add fields without changing the calling signature.

DynamicUpdateHandler implementation

Implement Update handlers dynamically using DynamicUpdateHandler. Register with Workflow.registerListener(Object). When registered, any Updates sent to the Workflow without a defined handler are delivered to the DynamicUpdateHandler. You can only register one Workflow.registerListener per Workflow Execution. Example: Workflow.registerListener((DynamicUpdateHandler)(updateName, encodedArgs) -> encodedArgs.get(0, String.class));

Non-type safe Workflow stub APIs

When you don't have access to the Workflow Definition or it isn't written in Java, use these non-type safe APIs: WorkflowClient.newUntypedWorkflowStub for client stubs and Workflow.newUntypedExternalWorkflowStub for external workflow stubs. Pass method names instead of method objects to WorkflowStub.query, WorkflowStub.signal, WorkflowStub.update, WorkflowStub.startUpdateWithStart, and WorkflowStub.executeUpdateWithStart.

Send Update from Client in PHP

To send an Update to a Workflow Execution from a Client, call the Update method annotated with #[UpdateMethod] from the Client code. Create a workflow stub with $workflowClient->newWorkflowStub(GreetingWorkflow::class, $workflowOptions), start it with $workflowClient->start($workflow), then call the Update method like $workflow->addGreeting('World').

UpdateValidatorMethod attribute in PHP

The #[UpdateValidatorMethod] attribute is used to validate Updates. Set the forUpdate argument to the name of the Update handler. The validator must accept the same input parameters as the Update handler and return void. It should throw an exception if validation fails.

Async Update with startUpdate in PHP

Use the stub method startUpdate() for Updates that will take a long time to execute or when you are not interested in the outcome. This returns an UpdateHandle immediately after receiving the validation result. For example: $handle = $stub->startUpdate('addGreeting', 'World'); $result = $handle->getResult(timeout: 2.5);

Update handler naming in PHP

The Update type defaults to the name of the method. To assign a custom Update type, use the #[UpdateMethod] attribute with the name parameter: #[UpdateMethod(name: 'pause')].

Update handler capabilities in PHP

Update handlers, unlike Query handlers, can change Workflow state. They can execute Activities, child Workflows, wait on timers, and perform other Workflow operations.

Dynamic Update handler registration in PHP

Update handlers can be registered dynamically using Workflow::registerUpdate(name: 'pause', handler: fn() => $this->paused = true, validator: fn() => $this->paused === false or throw new Exception('Workflow is already paused')). The third argument is an optional Update validator that must have the same parameters as the handler and throw an exception if validation fails.

UpdateOptions in PHP

UpdateOptions provides control over Update execution. Use UpdateOptions::new('updateName', LifecycleStage::StageCompleted)->withResultType(ResultClass::class) to specify the update name, lifecycle stage (when to wait for), and expected result type.

Query Workflow from Client in PHP

Use WorkflowStub to Query Workflow instances from Client code (can be applied to both running and closed Workflows). Create a stub with $workflowClient->newWorkflowStub(YourWorkflow::class, WorkflowOptions::new()), start the workflow, then call the Query method like $workflow->getCurrentState().

Query handler example with state tracking in PHP

Query handlers can track Workflow state by using #[QueryMethod] with a custom name like 'current_state'. The handler returns the current state value, which can be updated as the Workflow executes Activities, timers, or other operations. For example: #[QueryMethod('current_state')] public function getCurrentState(): string { return $this->currentState; }

Update in Temporal Workflow definition

An Update is an operation that can mutate the state of a Workflow Execution and return a response. It has a name (also called an Update type, which is a string), arguments, a response, and an optional validator. Arguments and response must be serializable.

Query handler restrictions in PHP

Query handlers must not include any logic that causes Command generation, such as executing Activities. Including such logic causes unexpected behavior.

UpdateMethod attribute in PHP

The #[UpdateMethod] attribute indicates that a method handles and responds to update requests. The method can accept multiple serializable input parameters (single parameter recommended) and return a serializable value or void.

Update-with-Start API in PHP

Update-with-Start sends an Update that checks if a Workflow with a given ID exists. If it exists, the Update is processed. If not, a new Workflow Execution is started with that ID, and the Update is processed before the main Workflow method executes. Use $workflowClient->updateWithStart(workflow: $stub, update: 'updateName', updateArgs: [$arg1, $arg2]). Returns once the requested Update wait stage is reached or times out.

Workflow::allHandlersFinished in PHP

Use Workflow::await(fn() => Workflow::allHandlersFinished()) in the main Workflow method to ensure all async Signal or Update handlers complete before the Workflow finishes. This prevents handlers from being interrupted mid-execution and allows clients to retrieve Update results successfully.

Send Signal to running Workflow from Client in PHP

To send Signals to already running Workflows, use $workflowClient->newRunningWorkflowStub(YourWorkflow::class, 'workflowID') or $workflowClient->newUntypedRunningWorkflowStub() with Workflow Id.

Send Signal from Temporal Client in PHP

To send a Signal to a Workflow Execution from a Client, call the Signal method annotated with #[SignalMethod] from the Client code. Use $workflowClient->newWorkflowStub() or $workflowClient->newUntypedWorkflowStub() to create a stub, then start the workflow with $workflowClient->start($workflow), and call the Signal method like $workflow->setValue(true). When a Signal is sent successfully, a WorkflowExecutionSignaled Event appears in the Event History of the receiving Workflow.

External Signal between Workflows in PHP

When an External Signal is sent from one Workflow to another, a SignalExternalWorkflowExecutionInitiated Event appears in the sender's Event History, and a WorkflowExecutionSignaled Event appears in the recipient's Event History.

Multiple methods with same attribute in PHP workflows

You can have more than one method with the same attribute in a Workflow interface, except for #[WorkflowMethod]. For example, a Workflow can have multiple #[SignalMethod] and #[QueryMethod] methods.

Signal handling with Workflow::await in PHP

Workflows listen for Signals by the Signal's name. Use the #[SignalMethod] attribute to handle Signals. A Signal handler can update workflow state, and the main Workflow method can wait for state changes using Workflow::await(fn()=> $this->value) to block execution until a condition becomes true.

Signal-With-Start API in PHP

Signal-With-Start is used from the Client. It takes a Workflow Id, Workflow arguments, a Signal name, and Signal arguments. Use $workflowClient->startWithSignal($workflow, 'signalName', [signal arguments], [start arguments]). If a running Workflow exists with the given Workflow Id, it will be signaled. If not, a new Workflow will be started and immediately signaled.

Update-with-Start WorkflowOptions requirements in PHP

For Update-with-Start, WorkflowOptions must include a Workflow Id Conflict Policy. Choose 'UseExisting' and use an idempotent Update handler to ensure code can be executed again in case of Client failure. Not all WorkflowOptions are allowed; for example, specifying a Cron Schedule will result in an error.

SignalMethod attribute in PHP

The #[SignalMethod] attribute indicates a method that reacts to external signals in a Workflow. It must have a void return type.

QueryMethod attribute in PHP

The #[QueryMethod] attribute indicates a method that reacts to synchronous query requests in a Workflow. It must have a non-void return type.

Query in Temporal Workflow definition

A Query is a synchronous operation used to get the state of a Workflow Execution. It has a name (also called a Query type, which is a string) and can have arguments that must be serializable.

Workflow::await to wait for conditions in PHP

Use Workflow::await(fn() => $condition) to block code execution until a condition returns true. This is useful in handlers that need to meet certain conditions before continuing, or in the main Workflow waiting for handlers to finish. The condition can be updated by any part of Workflow code including the main method, handlers, or child coroutines.

WorkflowInit constructor and WorkflowMethod parameter matching in PHP

When using #[WorkflowInit], the constructor and #[WorkflowMethod] must have the same parameters. For example, both must accept the same string $input parameter if that is the Workflow input type.

Workflow Mutex for handler concurrency control in PHP

Use Workflow::Mutex to prevent concurrent execution issues in Signal or Update handlers. Create a private Workflow\Mutex $mutex in the handler, then wrap critical sections with yield Workflow::runLocked($this->mutex, function() { /* critical code */ }). This ensures only one handler instance can execute a specific section at a time.

Give your agent this brain