Skip to content
Open
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ See the README.md file in each main sample directory for cut/paste Gradle comman
- [**HelloWorkflowTimer**](/core/src/main/java/io/temporal/samples/hello/HelloWorkflowTimer.java): Demonstrates how we can use workflow timer to restrict duration of workflow execution instead of workflow run/execution timeouts.
- [**Auto-Heartbeating**](/core/src/main/java/io/temporal/samples/autoheartbeat/): Demonstrates use of Auto-heartbeating utility via activity interceptor.
- [**HelloSignalWithStartAndWorkflowInit**](/core/src/main/java/io/temporal/samples/hello/HelloSignalWithStartAndWorkflowInit.java): Demonstrates how WorkflowInit can be useful with SignalWithStart to initialize workflow variables.
- [**HelloStandaloneActivity**](/core/src/main/java/io/temporal/samples/hello/HelloStandaloneActivity.java): Demonstrates how to execute a Standalone Activity directly from an ActivityClient, without a Workflow.

#### Scenario-based samples

Expand Down Expand Up @@ -147,6 +148,8 @@ Load client configuration from TOML files with programmatic overrides.

- [**Exclude Workflow/ActivityTypes from Interceptors**](/core/src/main/java/io/temporal/samples/excludefrominterceptor): Demonstrates how to exclude certain workflow / activity types from interceptors.

- [**Standalone Activities**](/core/src/main/java/io/temporal/samples/standaloneactivities): Demonstrates how to start, execute, list, and count Standalone Activities — Activities that run independently without a Workflow, using ActivityClient.

#### SDK Metrics

- [**Set up SDK metrics**](/core/src/main/java/io/temporal/samples/metrics): Demonstrates how to set up and scrape SDK metrics.
Expand Down
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ subprojects {
ext {
otelVersion = '1.30.1'
otelVersionAlpha = "${otelVersion}-alpha"
javaSDKVersion = '1.34.0'
javaSDKVersion = '1.35.0'
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on #773, I believe so.

camelVersion = '3.22.1'
jarVersion = '1.0.0'
}

repositories {
mavenLocal()
Comment thread
GregoryTravis marked this conversation as resolved.
maven {
url "https://oss.sonatype.org/content/repositories/snapshots/"
}
Expand Down
3 changes: 3 additions & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,7 @@ dependencies {
task execute(type: JavaExec) {
mainClass = findProperty("mainClass") ?: ""
classpath = sourceSets.main.runtimeClasspath
if (findProperty("args")) {
args findProperty("args").tokenize()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package io.temporal.samples.hello;

import io.temporal.activity.ActivityInterface;
import io.temporal.activity.ActivityMethod;
import io.temporal.client.ActivityClient;
import io.temporal.client.ActivityClientOptions;
import io.temporal.client.StartActivityOptions;
import io.temporal.client.WorkflowClient;
import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import java.io.IOException;
import java.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Sample Temporal application that executes a Standalone Activity — an Activity that runs
* independently, without being orchestrated by a Workflow. Requires a local instance of the
* Temporal service to be running.
*
* <p>Unlike regular Activities, a Standalone Activity is started directly from a Temporal Client
* using {@link ActivityClient}, not from inside a Workflow Definition. Writing the Activity and
* registering it with the Worker is identical in both cases.
*/
public class HelloStandaloneActivity {

static final String TASK_QUEUE = "HelloStandaloneActivityTaskQueue";
static final String ACTIVITY_ID = "hello-standalone-activity-id";

/**
* Activity interface. Writing a Standalone Activity is identical to writing an Activity
* orchestrated by a Workflow — the same Activity can be used for both.
*
* @see io.temporal.activity.ActivityInterface
* @see io.temporal.activity.ActivityMethod
*/
@ActivityInterface
public interface GreetingActivities {

// Define your activity method which can be called directly from a Temporal Client.
@ActivityMethod
String composeGreeting(String greeting, String name);
}

/** Simple activity implementation that concatenates two strings. */
public static class GreetingActivitiesImpl implements GreetingActivities {

private static final Logger log = LoggerFactory.getLogger(GreetingActivitiesImpl.class);

@Override
public String composeGreeting(String greeting, String name) {
log.info("Composing greeting...");
return greeting + ", " + name + "!";
}
}

public static void main(String[] args) {
// Load configuration from environment and files.
ClientConfigProfile profile;
try {
profile = ClientConfigProfile.load();
} catch (IOException e) {
throw new RuntimeException("Failed to load client configuration", e);
}

// gRPC stubs wrapper that talks to the temporal service.
WorkflowServiceStubs service =
WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());

// WorkflowClient is required to create a Worker.
WorkflowClient workflowClient =
WorkflowClient.newInstance(service, profile.toWorkflowClientOptions());

// Worker factory that can be used to create workers for specific task queues.
WorkerFactory factory = WorkerFactory.newInstance(workflowClient);

// Worker that listens on a task queue and hosts activity implementations.
Worker worker = factory.newWorker(TASK_QUEUE);

// Activities are stateless and thread safe. So a shared instance is used.
worker.registerActivitiesImplementations(new GreetingActivitiesImpl());

// Start listening to the activity task queue.
factory.start();

// ActivityClient executes standalone activities directly from application code,
// without a Workflow.
ActivityClient client =
ActivityClient.newInstance(
service,
ActivityClientOptions.newBuilder().setNamespace(profile.getNamespace()).build());

// Options specifying the activity ID, task queue, and timeout.
StartActivityOptions options =
StartActivityOptions.newBuilder()
.setId(ACTIVITY_ID)
.setTaskQueue(TASK_QUEUE)
.setStartToCloseTimeout(Duration.ofSeconds(10))
.build();

try {
// Execute the activity and wait for its result. The typed API uses an unbound method
// reference so the SDK can infer the activity type name and result type automatically.
String result =
client.execute(
GreetingActivities.class,
GreetingActivities::composeGreeting,
options,
"Hello",
"World");

System.out.println(result);
} finally {
// Shut down the worker before the service so polling threads stop cleanly.
factory.shutdown();
service.shutdown();
}
}
}
1 change: 1 addition & 0 deletions core/src/main/java/io/temporal/samples/hello/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ To run each hello world sample, use one of the following commands:
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloUpdate
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignalWithTimer
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloSignalWithStartAndWorkflowInit
./gradlew -q execute -PmainClass=io.temporal.samples.hello.HelloStandaloneActivity
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.temporal.samples.standaloneactivities;

import static io.temporal.samples.standaloneactivities.StandaloneActivityWorker.TASK_QUEUE;

import io.temporal.client.ActivityClient;
import io.temporal.client.ActivityClientOptions;
import io.temporal.client.ActivityExecutionCount;
import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import java.io.IOException;

/** Counts standalone activity executions on the task queue. */
public class CountActivities {

public static void main(String[] args) throws IOException {
ClientConfigProfile profile = ClientConfigProfile.load();
WorkflowServiceStubs service =
WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());

ActivityClient client =
ActivityClient.newInstance(
service,
ActivityClientOptions.newBuilder().setNamespace(profile.getNamespace()).build());

try {
ActivityExecutionCount resp = client.countExecutions("TaskQueue = '" + TASK_QUEUE + "'");

System.out.println("Total activities: " + resp.getCount());
resp.getGroups()
.forEach(
group ->
System.out.println("Group " + group.getGroupValues() + ": " + group.getCount()));
} finally {
service.shutdown();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.temporal.samples.standaloneactivities;

import static io.temporal.samples.standaloneactivities.StandaloneActivityWorker.TASK_QUEUE;

import io.temporal.client.ActivityClient;
import io.temporal.client.ActivityClientOptions;
import io.temporal.client.StartActivityOptions;
import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import java.io.IOException;
import java.time.Duration;

/**
* Executes a standalone activity and waits for the result. Requires a Worker running
* StandaloneActivityWorker.
*/
public class ExecuteActivity {

static final String ACTIVITY_ID = "standalone-activity-id";

public static void main(String[] args) throws IOException {
ClientConfigProfile profile = ClientConfigProfile.load();
WorkflowServiceStubs service =
WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());

ActivityClient client =
ActivityClient.newInstance(
service,
ActivityClientOptions.newBuilder().setNamespace(profile.getNamespace()).build());

StartActivityOptions options =
StartActivityOptions.newBuilder()
.setId(ACTIVITY_ID)
.setTaskQueue(TASK_QUEUE)
.setStartToCloseTimeout(Duration.ofSeconds(10))
.build();

try {
String result =
client.execute(
GreetingActivities.class,
GreetingActivities::composeGreeting,
options,
"Hello",
"World");
System.out.println("Activity result: " + result);
} finally {
service.shutdown();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.temporal.samples.standaloneactivities;

import io.temporal.activity.ActivityInterface;
import io.temporal.activity.ActivityMethod;

/** Activity interface shared by all programs in this sample. */
@ActivityInterface
public interface GreetingActivities {

@ActivityMethod
String composeGreeting(String greeting, String name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.temporal.samples.standaloneactivities;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** Activity implementation. */
public class GreetingActivitiesImpl implements GreetingActivities {

private static final Logger log = LoggerFactory.getLogger(GreetingActivitiesImpl.class);

@Override
public String composeGreeting(String greeting, String name) {
log.info("Composing greeting...");
return greeting + ", " + name + "!";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.temporal.samples.standaloneactivities;

import static io.temporal.samples.standaloneactivities.StandaloneActivityWorker.TASK_QUEUE;

import io.temporal.client.ActivityClient;
import io.temporal.client.ActivityClientOptions;
import io.temporal.client.ActivityExecutionMetadata;
import io.temporal.envconfig.ClientConfigProfile;
import io.temporal.serviceclient.WorkflowServiceStubs;
import java.io.IOException;
import java.util.stream.Stream;

/** Lists standalone activity executions on the task queue. */
public class ListActivities {

public static void main(String[] args) throws IOException {
ClientConfigProfile profile = ClientConfigProfile.load();
WorkflowServiceStubs service =
WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions());

ActivityClient client =
ActivityClient.newInstance(
service,
ActivityClientOptions.newBuilder().setNamespace(profile.getNamespace()).build());

try (Stream<ActivityExecutionMetadata> activities =
client.listExecutions("TaskQueue = '" + TASK_QUEUE + "'")) {
activities.forEach(
info ->
System.out.printf(
"ActivityID: %s, Type: %s, Status: %s%n",
info.getActivityId(), info.getActivityType(), info.getStatus()));
} finally {
service.shutdown();
}
}
}
Loading
Loading