mirror of
https://github.com/temporalio/skill-temporal-developer.git
synced 2026-09-14 13:52:58 +08:00
0c8586b4c2
* Add Java SDK reference files (11 files) Create complete Java reference documentation covering: - java.md: Entry point with quick start tutorial, key concepts - patterns.md: 17 patterns (signals, queries, updates, child workflows, saga, cancellation scopes, heartbeating, etc.) - determinism.md: Safe alternatives table, forbidden operations - determinism-protection.md: Convention-based enforcement (no sandbox) - error-handling.md: ApplicationFailure, retry/timeout config - gotchas.md: Non-deterministic operations, cancellation, heartbeating - testing.md: TestWorkflowEnvironment, Mockito mocking, replay testing - versioning.md: Workflow.getVersion(), worker versioning - data-handling.md: Jackson, PayloadConverter, encryption, search attributes - observability.md: SLF4J logging, Micrometer metrics - advanced-features.md: Schedules, async completion, worker tuning Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix Java alignment issues from self-review - Reduce gotchas.md Non-Deterministic Operations from ~94 lines to ~12 (reference determinism.md instead of duplicating) - Remove Workflow Failure Exception Types duplication from error-handling.md (keep only in advanced-features.md) - Expand versioning.md Worker Versioning with Key Concepts, PINNED vs AUTO_UPGRADE, Deployment Strategies subsections - Fix section names to match Python reference style: Activity Heartbeat Details, Handling Activity Errors, Retry Policy Configuration, Workflow Test Environment, Mocking Activities, Workflow Replay Testing - Reduce data-handling.md Payload Encryption verbosity - Reduce observability.md Logger Customization verbosity - Reduce testing.md to single approach per section - Rename determinism.md "Convention-Based Enforcement" to "SDK Protection" - Fix handler guidance in patterns.md to match Python Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix correctness issues in Java reference files - patterns.md: Fix Queries section — ActivityStub → typed interface (Workflow.newActivityStub returns the typed interface, not ActivityStub) - data-handling.md: Add missing ProtobufPayloadConverter to default converter chain (4th of 5 converters) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add Java to SKILL.md and core/determinism.md - SKILL.md: Add "Temporal Java" trigger phrase, update Overview to list Java, add Java entry to Getting Started references - core/determinism.md: Add Java entry to SDK Protection Mechanisms (no sandbox, convention-based, NonDeterministicException at replay) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Apply manual editorial fixes to Java references - java.md: Remove "Understanding Replay" section (covered by Overview), simplify File Organization note (no sandbox rationale) - gotchas.md: Move Heartbeating before Cancellation, make Wrong Retry Classification brief with reference (not inline examples) - error-handling.md: Remove editorializing from Workflow Failure note - determinism-protection.md: Remove cross-language comparison paragraph (state Java's approach on its own terms) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add temporal-workflowcheck static analysis to Java determinism docs - determinism-protection.md: Add "Static Analysis with temporal-workflowcheck" section with Gradle/Maven setup, manual run, and suppression instructions. Beta warning included. - determinism.md: Update overview and SDK Protection to reference workflowcheck - core/determinism.md: Update Java entry in SDK Protection Mechanisms Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Integrate feedback from Go PR into Java patterns - Updates: Add validator note — validators must not mutate state or block (matches note added to Python, TypeScript, Go, and core) - Saga Pattern: Use Workflow.newDetachedCancellationScope() for compensations so they execute even if the workflow is cancelled (mirrors Go's workflow.NewDisconnectedContext pattern) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> * docs: add @WorkflowInit description to java.md Key Concepts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * mark java as supported * Apply suggestions from code review Co-authored-by: Brian Strauch <brian@brianstrauch.com> * strongly recommend java 21+ * Softened stance on static checker and replay testing. * address python/typescript sandboxing comment --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Brian Strauch <brian.strauch@temporal.io> Co-authored-by: Brian Strauch <brian@brianstrauch.com>
168 lines
5.7 KiB
Markdown
168 lines
5.7 KiB
Markdown
# 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.
|