Cancel Activity Temporal Typescript

6 min read Oct 03, 2024
Cancel Activity Temporal Typescript

Canceling Activities in Temporal with TypeScript

Temporal is a powerful framework for building reliable and scalable distributed applications. One of its key features is the concept of "activities," which represent long-running tasks that can be executed asynchronously. Sometimes, however, you might need to cancel an activity before it completes. This article will delve into the techniques and best practices for effectively canceling activities in Temporal, specifically using TypeScript.

Why Cancel Activities?

There are several common scenarios where canceling an activity becomes necessary:

  • User Request: A user might request to stop a long-running process, like a file upload or a complex calculation.
  • External Events: External events, such as a change in system state or a timeout, might trigger the need to cancel an activity.
  • Error Handling: If an activity encounters an error, you might want to cancel it to prevent further execution or resource consumption.
  • Workflow Termination: When a workflow itself is terminated, either intentionally or due to failure, all its running activities should be canceled.

How to Cancel Activities in Temporal with TypeScript?

Temporal provides mechanisms for both initiating and handling activity cancellation.

1. Initiating Activity Cancellation

The primary way to cancel an activity is through the workflow code. Workflows have a cancelActivity method which signals the cancellation request to the activity.

import { Workflow } from "@temporalio/sdk/workflow";

async function myWorkflow() {
  const activityHandle = await Workflow.startActivity(
    "myActivity",
    "some input"
  );

  // ... Perform some logic

  // Cancel the activity
  await Workflow.cancelActivity(activityHandle);
}

In this example, Workflow.startActivity returns an activity handle that represents the running activity. This handle is then used with Workflow.cancelActivity to initiate cancellation.

2. Handling Cancellation Requests in Activities

Activities themselves need to be designed to respond to cancellation requests. Here's how:

import { Activity, ActivityMethod } from "@temporalio/sdk/activity";

@Activity({ taskQueue: "myTaskQueue" })
class MyActivity {
  @ActivityMethod()
  async execute(input: string): Promise {
    // ... Perform activity logic

    try {
      // ... Process the activity
    } catch (error) {
      // ... Handle errors
    } finally {
      // Check if cancellation is requested
      if (Activity.isCancellationRequested()) {
        console.log("Activity cancellation requested. Cleaning up...");
        // ... Perform any cleanup or final actions
      }
    }
  }
}
  • Activity.isCancellationRequested(): This method allows the activity to check if a cancellation request has been sent.
  • finally Block: The finally block is crucial to execute cleanup tasks even if the activity encounters an error or is canceled.
  • Promise.race for Graceful Cancellation: For activities that perform long-running operations, you can use Promise.race to effectively handle cancellation:
import { Activity, ActivityMethod } from "@temporalio/sdk/activity";

@Activity({ taskQueue: "myTaskQueue" })
class MyActivity {
  @ActivityMethod()
  async execute(input: string): Promise {
    // ... Perform activity logic

    const cancellationPromise = new Promise((resolve) => {
      if (Activity.isCancellationRequested()) {
        resolve();
      }
    });

    try {
      return await Promise.race([
        // ... Process the activity logic
        cancellationPromise,
      ]);
    } finally {
      // ... Perform any cleanup or final actions
    }
  }
}

This approach ensures that the activity checks for cancellation periodically and responds accordingly, preventing the activity from running indefinitely.

Best Practices for Cancellation

  • Use Cancellation Tokens: For more complex scenarios where you need to manage multiple cancellation sources, consider using Cancellation Tokens. These can be used to propagate cancellation signals and make cleanup operations more robust.
  • Perform Cleanup Actions: Ensure that activities perform necessary cleanup actions when canceled. This might include releasing resources, updating state, or logging relevant information.
  • Retry on Cancellation: If possible, you can retry activities after a cancellation to ensure they complete. However, this might not be suitable for all scenarios.
  • Idempotency: Design activities to be idempotent. This means that an activity can be executed multiple times without causing unintended side effects. This is important when handling retries or cancellations, ensuring that the activity does not perform actions redundantly.

Conclusion

Canceling activities in Temporal is essential for managing long-running tasks and ensuring workflow reliability. By implementing the appropriate techniques and following best practices, you can effectively control the execution of your activities and handle cancellations gracefully. This results in robust and resilient workflows that can adapt to various situations and conditions.