Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Appropriately adjust the installation directory based on your coding agent.
- [x] Python ✅
- [x] TypeScript ✅
- [x] Go ✅
- [ ] Java 🚧 ([PR](https://github.com/temporalio/skill-temporal-developer/pull/42))
- [x] Java
- [ ] .NET 🚧 ([PR](https://github.com/temporalio/skill-temporal-developer/pull/39))
- [ ] Ruby 🚧 ([PR](https://github.com/temporalio/skill-temporal-developer/pull/41))
- [ ] PHP 🚧 ([PR](https://github.com/temporalio/skill-temporal-developer/pull/40))
5 changes: 3 additions & 2 deletions SKILL.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
name: temporal-developer
description: This skill should be used when the user asks to "create a Temporal workflow", "write a Temporal activity", "debug stuck workflow", "fix non-determinism error", "Temporal Python", "Temporal TypeScript", "Temporal Go", "Temporal Golang", "workflow replay", "activity timeout", "signal workflow", "query workflow", "worker not starting", "activity keeps retrying", "Temporal heartbeat", "continue-as-new", "child workflow", "saga pattern", "workflow versioning", "durable execution", "reliable distributed systems", or mentions Temporal SDK development.
description: This skill should be used when the user asks to "create a Temporal workflow", "write a Temporal activity", "debug stuck workflow", "fix non-determinism error", "Temporal Python", "Temporal TypeScript", "Temporal Go", "Temporal Golang", "Temporal Java", "workflow replay", "activity timeout", "signal workflow", "query workflow", "worker not starting", "activity keeps retrying", "Temporal heartbeat", "continue-as-new", "child workflow", "saga pattern", "workflow versioning", "durable execution", "reliable distributed systems", or mentions Temporal SDK development.
version: 0.1.0
---

# Skill: temporal-developer

## Overview

Temporal is a durable execution platform that makes workflows survive failures automatically. This skill provides guidance for building Temporal applications in Python, TypeScript, and Go.
Temporal is a durable execution platform that makes workflows survive failures automatically. This skill provides guidance for building Temporal applications in Python, TypeScript, Go, and Java.

## Core Architecture

Expand Down Expand Up @@ -92,6 +92,7 @@ Once you've downloaded the file, extract the downloaded archive and add the temp
1. First, read the getting started guide for the language you are working in:
- Python -> read `references/python/python.md`
- TypeScript -> read `references/typescript/typescript.md`
- Java -> read `references/java/java.md`
- Go -> read `references/go/go.md`
2. Second, read appropriate `core` and language-specific references for the task at hand.

Expand Down
3 changes: 2 additions & 1 deletion references/core/determinism.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,11 @@ In Temporal, activities are the primary mechanism for making non-deterministic c
For a few simple cases, like timestamps, random values, UUIDs, etc. the Temporal SDK in your language may provide durable variants that are simple to use. See `references/{your_language}/determinism.md` for the language you are working in for more info.

## SDK Protection Mechanisms
Each Temporal SDK language provides a protection mechanism to make it easier to catch non-determinism errors earlier in development:
Each Temporal SDK language provides a different level of protection against non-determinism:

- Python: The Python SDK runs workflows in a sandbox that intercepts and aborts non-deterministic calls early at runtime.
- TypeScript: The TypeScript SDK runs workflows in an isolated V8 sandbox, intercepting many common sources of non-determinism and replacing them automatically with deterministic variants.
- Java: The Java SDK has no sandbox. Determinism is enforced by developer conventions — the SDK provides `Workflow.*` APIs as safe alternatives (e.g., `Workflow.sleep()` instead of `Thread.sleep()`), and non-determinism is only detected at replay time via `NonDeterministicException`. A static analysis tool (`temporal-workflowcheck`, beta) can catch violations at build time. Cooperative threading under a global lock eliminates the need for synchronization.
- Go: The Go SDK has no runtime sandbox. Therefore, non-determinism bugs will never be immediately appararent, and are usually only observable during replay. The optional `workflowcheck` static analysis tool can be used to check for many sources of non-determinism at compile time.

Regardless of which SDK you are using, it is your responsibility to ensure that workflow code does not contain sources of non-determinism. Use SDK-specific tools as well as replay tests for doing so.
Expand Down
167 changes: 167 additions & 0 deletions references/java/advanced-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# Java SDK Advanced Features

## Schedules

Create recurring workflow executions.

```java
import io.temporal.client.schedules.*;

ScheduleClient scheduleClient = ScheduleClient.newInstance(service);

// Create a schedule
String scheduleId = "daily-report";
ScheduleHandle handle = scheduleClient.createSchedule(
scheduleId,
Schedule.newBuilder()
.setAction(
ScheduleActionStartWorkflow.newBuilder()
.setWorkflowType(DailyReportWorkflow.class)
.setOptions(
WorkflowOptions.newBuilder()
.setWorkflowId("daily-report")
.setTaskQueue("reports")
.build()
)
.build()
)
.setSpec(
ScheduleSpec.newBuilder()
.setIntervals(
List.of(new ScheduleIntervalSpec(Duration.ofDays(1)))
)
.build()
)
.build(),
ScheduleOptions.newBuilder().build()
);

// Manage schedules
ScheduleHandle scheduleHandle = scheduleClient.getHandle(scheduleId);
scheduleHandle.pause("Maintenance window");
scheduleHandle.unpause();
scheduleHandle.trigger(); // Run immediately
scheduleHandle.delete();
```

## Async Activity Completion

For activities that complete asynchronously (e.g., human tasks, external callbacks).
If you configure a heartbeat timeout on this activity, the external completer is responsible for sending heartbeats via the async handle.

**Note:** If the external system can reliably Signal back with the result and doesn't need to Heartbeat or receive Cancellation, consider using **signals** instead.

```java
public class ApprovalActivitiesImpl implements ApprovalActivities {
@Override
public String requestApproval(String requestId) {
ActivityExecutionContext ctx = Activity.getExecutionContext();

// Get task token for async completion
byte[] taskToken = ctx.getTaskToken();

// Store task token for later completion (e.g., in database)
storeTaskToken(requestId, taskToken);

// Mark this activity as waiting for external completion
ctx.doNotCompleteOnReturn();

return null; // Return value is ignored
}
}

// Later, complete the activity from another process
public void completeApproval(String requestId, boolean approved) {
WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
WorkflowClient client = WorkflowClient.newInstance(service);

ActivityCompletionClient completionClient = client.newActivityCompletionClient();

byte[] taskToken = getTaskToken(requestId);

if (approved) {
completionClient.complete(taskToken, "approved");
} else {
completionClient.completeExceptionally(
taskToken,
new RuntimeException("Rejected")
);
}
}
```

## Worker Tuning

Configure worker performance settings.

```java
WorkerOptions workerOptions = WorkerOptions.newBuilder()
// Max concurrent workflow task executions (default: 200)
.setMaxConcurrentWorkflowTaskExecutionSize(200)
// Max concurrent activity executions (default: 200)
.setMaxConcurrentActivityExecutionSize(200)
// Max concurrent local activity executions (default: 200)
.setMaxConcurrentLocalActivityExecutionSize(200)
// Max workflow task pollers (default: 5)
.setMaxConcurrentWorkflowTaskPollers(5)
// Max activity task pollers (default: 5)
.setMaxConcurrentActivityTaskPollers(5)
.build();

WorkerFactory factory = WorkerFactory.newInstance(client);
Worker worker = factory.newWorker("my-queue", workerOptions);
worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class);
worker.registerActivitiesImplementations(new MyActivitiesImpl());
factory.start();
```

## Workflow Failure Exception Types

Control which exceptions cause workflow failures vs workflow task failures.

By default, only `ApplicationFailure` (and its subclasses) fail the workflow execution. All other exceptions fail the **workflow task**, causing the task to retry indefinitely until the code is fixed or the workflow is terminated.

### Per-Workflow Configuration

Use `WorkflowImplementationOptions` to specify which exception types should fail the workflow:

```java
Worker worker = factory.newWorker("my-queue");
worker.registerWorkflowImplementationTypes(
WorkflowImplementationOptions.newBuilder()
.setFailWorkflowExceptionTypes(
IllegalArgumentException.class,
CustomBusinessException.class
)
.build(),
MyWorkflowImpl.class
);
```

With this configuration, `IllegalArgumentException` and `CustomBusinessException` thrown from the workflow will fail the workflow execution instead of just the workflow task.

### Worker-Level Configuration

Apply to all workflows registered on the worker:

```java
WorkerFactoryOptions factoryOptions = WorkerFactoryOptions.newBuilder()
.setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ofSeconds(10))
.build();
WorkerFactory factory = WorkerFactory.newInstance(client, factoryOptions);

Worker worker = factory.newWorker("my-queue");
// Register each workflow type with its own failure exception types
worker.registerWorkflowImplementationTypes(
WorkflowImplementationOptions.newBuilder()
.setFailWorkflowExceptionTypes(
IllegalArgumentException.class,
CustomBusinessException.class
)
.build(),
MyWorkflowImpl.class,
AnotherWorkflowImpl.class
);
```

- **Tip for testing:** Set `setFailWorkflowExceptionTypes(Throwable.class)` so any unhandled exception fails the workflow immediately rather than retrying the workflow task forever. This surfaces bugs faster.
Loading